aboutsummaryrefslogtreecommitdiffstats
path: root/lib/erl_interface
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/erl_interface
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/erl_interface')
-rw-r--r--lib/erl_interface/AUTHORS9
-rw-r--r--lib/erl_interface/Makefile32
l---------lib/erl_interface/aclocal.m41
-rw-r--r--lib/erl_interface/configure.in443
-rw-r--r--lib/erl_interface/doc/html/.gitignore0
-rw-r--r--lib/erl_interface/doc/man1/.gitignore0
-rw-r--r--lib/erl_interface/doc/man3/.gitignore0
-rw-r--r--lib/erl_interface/doc/pdf/.gitignore0
-rw-r--r--lib/erl_interface/doc/src/Makefile129
-rw-r--r--lib/erl_interface/doc/src/book.xml49
-rw-r--r--lib/erl_interface/doc/src/ei.xml728
-rw-r--r--lib/erl_interface/doc/src/ei_connect.xml639
-rw-r--r--lib/erl_interface/doc/src/ei_users_guide.xml612
-rw-r--r--lib/erl_interface/doc/src/erl_call.xml240
-rw-r--r--lib/erl_interface/doc/src/erl_connect.xml566
-rw-r--r--lib/erl_interface/doc/src/erl_error.xml136
-rw-r--r--lib/erl_interface/doc/src/erl_eterm.xml675
-rw-r--r--lib/erl_interface/doc/src/erl_format.xml141
-rw-r--r--lib/erl_interface/doc/src/erl_global.xml141
-rw-r--r--lib/erl_interface/doc/src/erl_interface.xml625
-rw-r--r--lib/erl_interface/doc/src/erl_malloc.xml200
-rw-r--r--lib/erl_interface/doc/src/erl_marshal.xml272
-rw-r--r--lib/erl_interface/doc/src/fascicules.xml24
-rw-r--r--lib/erl_interface/doc/src/make.dep24
-rw-r--r--lib/erl_interface/doc/src/note.gifbin0 -> 1539 bytes
-rw-r--r--lib/erl_interface/doc/src/notes.xml535
-rw-r--r--lib/erl_interface/doc/src/notes_history.xml367
-rw-r--r--lib/erl_interface/doc/src/part.xml33
-rw-r--r--lib/erl_interface/doc/src/part_erl_interface.xml33
-rw-r--r--lib/erl_interface/doc/src/part_notes.xml38
-rw-r--r--lib/erl_interface/doc/src/part_notes_history.xml36
-rw-r--r--lib/erl_interface/doc/src/ref_man.xml55
-rw-r--r--lib/erl_interface/doc/src/ref_man_ei.xml47
-rw-r--r--lib/erl_interface/doc/src/ref_man_erl_interface.xml52
-rw-r--r--lib/erl_interface/doc/src/registry.xml611
-rw-r--r--lib/erl_interface/doc/src/warning.gifbin0 -> 1498 bytes
-rw-r--r--lib/erl_interface/include/ei.h785
-rw-r--r--lib/erl_interface/include/ei_connect.h26
-rw-r--r--lib/erl_interface/include/eicode.h26
-rw-r--r--lib/erl_interface/include/erl_interface.h449
-rw-r--r--lib/erl_interface/info2
-rw-r--r--lib/erl_interface/priv/.gitignore0
-rw-r--r--lib/erl_interface/src/INSTALL182
-rw-r--r--lib/erl_interface/src/Makefile31
-rw-r--r--lib/erl_interface/src/Makefile.in903
-rw-r--r--lib/erl_interface/src/README186
-rw-r--r--lib/erl_interface/src/README.internal285
l---------lib/erl_interface/src/auxdir/config.guess1
-rw-r--r--lib/erl_interface/src/auxdir/config.h.in277
l---------lib/erl_interface/src/auxdir/config.sub1
l---------lib/erl_interface/src/auxdir/install-sh1
-rw-r--r--lib/erl_interface/src/connect/ei_connect.c1738
-rw-r--r--lib/erl_interface/src/connect/ei_connect_int.h114
-rw-r--r--lib/erl_interface/src/connect/ei_resolve.c645
-rw-r--r--lib/erl_interface/src/connect/ei_resolve.h24
-rw-r--r--lib/erl_interface/src/connect/eirecv.c280
-rw-r--r--lib/erl_interface/src/connect/eirecv.h26
-rw-r--r--lib/erl_interface/src/connect/eisend.h41
-rw-r--r--lib/erl_interface/src/connect/send.c125
-rw-r--r--lib/erl_interface/src/connect/send_exit.c101
-rw-r--r--lib/erl_interface/src/connect/send_reg.c122
-rw-r--r--lib/erl_interface/src/decode/decode_atom.c42
-rw-r--r--lib/erl_interface/src/decode/decode_big.c331
-rw-r--r--lib/erl_interface/src/decode/decode_bignum.c75
-rw-r--r--lib/erl_interface/src/decode/decode_binary.c42
-rw-r--r--lib/erl_interface/src/decode/decode_boolean.c57
-rw-r--r--lib/erl_interface/src/decode/decode_char.c69
-rw-r--r--lib/erl_interface/src/decode/decode_double.c39
-rw-r--r--lib/erl_interface/src/decode/decode_fun.c123
-rw-r--r--lib/erl_interface/src/decode/decode_intlist.c82
-rw-r--r--lib/erl_interface/src/decode/decode_list_header.c45
-rw-r--r--lib/erl_interface/src/decode/decode_long.c86
-rw-r--r--lib/erl_interface/src/decode/decode_longlong.c100
-rw-r--r--lib/erl_interface/src/decode/decode_pid.c54
-rw-r--r--lib/erl_interface/src/decode/decode_port.c53
-rw-r--r--lib/erl_interface/src/decode/decode_ref.c94
-rw-r--r--lib/erl_interface/src/decode/decode_skip.c90
-rw-r--r--lib/erl_interface/src/decode/decode_skip.h27
-rw-r--r--lib/erl_interface/src/decode/decode_string.c85
-rw-r--r--lib/erl_interface/src/decode/decode_trace.c43
-rw-r--r--lib/erl_interface/src/decode/decode_tuple_header.c47
-rw-r--r--lib/erl_interface/src/decode/decode_ulong.c78
-rw-r--r--lib/erl_interface/src/decode/decode_ulonglong.c83
-rw-r--r--lib/erl_interface/src/decode/decode_version.c38
-rw-r--r--lib/erl_interface/src/depend.mk1133
-rw-r--r--lib/erl_interface/src/eidefs.mk.in31
-rw-r--r--lib/erl_interface/src/encode/eicode.h69
-rw-r--r--lib/erl_interface/src/encode/encode_atom.c51
-rw-r--r--lib/erl_interface/src/encode/encode_big.c84
-rw-r--r--lib/erl_interface/src/encode/encode_bignum.c81
-rw-r--r--lib/erl_interface/src/encode/encode_binary.c41
-rw-r--r--lib/erl_interface/src/encode/encode_boolean.c47
-rw-r--r--lib/erl_interface/src/encode/encode_char.c38
-rw-r--r--lib/erl_interface/src/encode/encode_double.c42
-rw-r--r--lib/erl_interface/src/encode/encode_fun.c82
-rw-r--r--lib/erl_interface/src/encode/encode_list_header.c45
-rw-r--r--lib/erl_interface/src/encode/encode_long.c64
-rw-r--r--lib/erl_interface/src/encode/encode_longlong.c103
-rw-r--r--lib/erl_interface/src/encode/encode_pid.c52
-rw-r--r--lib/erl_interface/src/encode/encode_port.c51
-rw-r--r--lib/erl_interface/src/encode/encode_ref.c59
-rw-r--r--lib/erl_interface/src/encode/encode_string.c77
-rw-r--r--lib/erl_interface/src/encode/encode_trace.c36
-rw-r--r--lib/erl_interface/src/encode/encode_tuple_header.c49
-rw-r--r--lib/erl_interface/src/encode/encode_ulong.c57
-rw-r--r--lib/erl_interface/src/encode/encode_ulonglong.c94
-rw-r--r--lib/erl_interface/src/encode/encode_version.c35
-rw-r--r--lib/erl_interface/src/epmd/ei_epmd.h66
-rw-r--r--lib/erl_interface/src/epmd/epmd_port.c299
-rw-r--r--lib/erl_interface/src/epmd/epmd_publish.c228
-rw-r--r--lib/erl_interface/src/epmd/epmd_unpublish.c106
-rw-r--r--lib/erl_interface/src/legacy/decode_term.c142
-rw-r--r--lib/erl_interface/src/legacy/encode_term.c53
-rw-r--r--lib/erl_interface/src/legacy/erl_config.h22
-rw-r--r--lib/erl_interface/src/legacy/erl_connect.c457
-rw-r--r--lib/erl_interface/src/legacy/erl_connect.h24
-rw-r--r--lib/erl_interface/src/legacy/erl_error.c180
-rw-r--r--lib/erl_interface/src/legacy/erl_error.h25
-rw-r--r--lib/erl_interface/src/legacy/erl_eterm.c1308
-rw-r--r--lib/erl_interface/src/legacy/erl_eterm.h61
-rw-r--r--lib/erl_interface/src/legacy/erl_fix_alloc.c193
-rw-r--r--lib/erl_interface/src/legacy/erl_fix_alloc.h26
-rw-r--r--lib/erl_interface/src/legacy/erl_format.c729
-rw-r--r--lib/erl_interface/src/legacy/erl_format.h22
-rw-r--r--lib/erl_interface/src/legacy/erl_global.h27
-rw-r--r--lib/erl_interface/src/legacy/erl_internal.h47
-rw-r--r--lib/erl_interface/src/legacy/erl_malloc.c239
-rw-r--r--lib/erl_interface/src/legacy/erl_malloc.h26
-rw-r--r--lib/erl_interface/src/legacy/erl_marshal.c2117
-rw-r--r--lib/erl_interface/src/legacy/erl_marshal.h29
-rw-r--r--lib/erl_interface/src/legacy/erl_resolve.c106
-rw-r--r--lib/erl_interface/src/legacy/erl_timeout.c161
-rw-r--r--lib/erl_interface/src/legacy/erl_timeout.h74
-rw-r--r--lib/erl_interface/src/legacy/global_names.c109
-rw-r--r--lib/erl_interface/src/legacy/global_register.c110
-rw-r--r--lib/erl_interface/src/legacy/global_unregister.c102
-rw-r--r--lib/erl_interface/src/legacy/global_whereis.c91
-rw-r--r--lib/erl_interface/src/legacy/portability.h33
-rw-r--r--lib/erl_interface/src/misc/ei_compat.c39
-rw-r--r--lib/erl_interface/src/misc/ei_decode_term.c156
-rw-r--r--lib/erl_interface/src/misc/ei_decode_term.h31
-rw-r--r--lib/erl_interface/src/misc/ei_format.c466
-rw-r--r--lib/erl_interface/src/misc/ei_format.h26
-rw-r--r--lib/erl_interface/src/misc/ei_internal.h157
-rw-r--r--lib/erl_interface/src/misc/ei_locking.c164
-rw-r--r--lib/erl_interface/src/misc/ei_locking.h76
-rw-r--r--lib/erl_interface/src/misc/ei_malloc.c41
-rw-r--r--lib/erl_interface/src/misc/ei_malloc.h28
-rw-r--r--lib/erl_interface/src/misc/ei_portio.c377
-rw-r--r--lib/erl_interface/src/misc/ei_portio.h35
-rw-r--r--lib/erl_interface/src/misc/ei_printterm.c342
-rw-r--r--lib/erl_interface/src/misc/ei_printterm.h24
-rw-r--r--lib/erl_interface/src/misc/ei_pthreads.c226
-rw-r--r--lib/erl_interface/src/misc/ei_trace.c56
-rw-r--r--lib/erl_interface/src/misc/ei_trace.h26
-rw-r--r--lib/erl_interface/src/misc/ei_x_encode.c255
-rw-r--r--lib/erl_interface/src/misc/ei_x_encode.h31
-rw-r--r--lib/erl_interface/src/misc/eidef.h51
-rw-r--r--lib/erl_interface/src/misc/eiext.h35
-rw-r--r--lib/erl_interface/src/misc/eimd5.c319
-rw-r--r--lib/erl_interface/src/misc/eimd5.h48
-rw-r--r--lib/erl_interface/src/misc/get_type.c149
-rw-r--r--lib/erl_interface/src/misc/putget.h85
-rw-r--r--lib/erl_interface/src/misc/show_msg.c584
-rw-r--r--lib/erl_interface/src/misc/show_msg.h27
-rw-r--r--lib/erl_interface/src/not_used/ei_send.c104
-rw-r--r--lib/erl_interface/src/not_used/ei_send_reg.c107
-rw-r--r--lib/erl_interface/src/not_used/send_link.c102
-rw-r--r--lib/erl_interface/src/not_used/whereis.c70
-rw-r--r--lib/erl_interface/src/prog/ei_fake_prog.c303
-rw-r--r--lib/erl_interface/src/prog/erl_call.c906
-rw-r--r--lib/erl_interface/src/prog/erl_fake_prog.c250
-rw-r--r--lib/erl_interface/src/prog/erl_start.c735
-rw-r--r--lib/erl_interface/src/prog/erl_start.h46
-rw-r--r--lib/erl_interface/src/registry/hash.h47
-rw-r--r--lib/erl_interface/src/registry/hash_dohash.c45
-rw-r--r--lib/erl_interface/src/registry/hash_foreach.c44
-rw-r--r--lib/erl_interface/src/registry/hash_freetab.c58
-rw-r--r--lib/erl_interface/src/registry/hash_insert.c108
-rw-r--r--lib/erl_interface/src/registry/hash_isprime.c57
-rw-r--r--lib/erl_interface/src/registry/hash_lookup.c42
-rw-r--r--lib/erl_interface/src/registry/hash_newtab.c52
-rw-r--r--lib/erl_interface/src/registry/hash_remove.c87
-rw-r--r--lib/erl_interface/src/registry/hash_resize.c67
-rw-r--r--lib/erl_interface/src/registry/hash_rlookup.c43
-rw-r--r--lib/erl_interface/src/registry/reg.h46
-rw-r--r--lib/erl_interface/src/registry/reg_close.c68
-rw-r--r--lib/erl_interface/src/registry/reg_delete.c36
-rw-r--r--lib/erl_interface/src/registry/reg_dirty.c36
-rw-r--r--lib/erl_interface/src/registry/reg_dump.c321
-rw-r--r--lib/erl_interface/src/registry/reg_free.c47
-rw-r--r--lib/erl_interface/src/registry/reg_get.c94
-rw-r--r--lib/erl_interface/src/registry/reg_getf.c35
-rw-r--r--lib/erl_interface/src/registry/reg_geti.c35
-rw-r--r--lib/erl_interface/src/registry/reg_getp.c39
-rw-r--r--lib/erl_interface/src/registry/reg_gets.c38
-rw-r--r--lib/erl_interface/src/registry/reg_make.c49
-rw-r--r--lib/erl_interface/src/registry/reg_open.c41
-rw-r--r--lib/erl_interface/src/registry/reg_purge.c76
-rw-r--r--lib/erl_interface/src/registry/reg_resize.c36
-rw-r--r--lib/erl_interface/src/registry/reg_restore.c323
-rw-r--r--lib/erl_interface/src/registry/reg_set.c78
-rw-r--r--lib/erl_interface/src/registry/reg_setf.c61
-rw-r--r--lib/erl_interface/src/registry/reg_seti.c62
-rw-r--r--lib/erl_interface/src/registry/reg_setp.c62
-rw-r--r--lib/erl_interface/src/registry/reg_sets.c65
-rw-r--r--lib/erl_interface/src/registry/reg_stat.c41
-rw-r--r--lib/erl_interface/src/registry/reg_tabstat.c37
-rw-r--r--lib/erl_interface/vsn.mk1
209 files changed, 34134 insertions, 0 deletions
diff --git a/lib/erl_interface/AUTHORS b/lib/erl_interface/AUTHORS
new file mode 100644
index 0000000000..c8ad36400d
--- /dev/null
+++ b/lib/erl_interface/AUTHORS
@@ -0,0 +1,9 @@
+Original Authors and Contributors:
+
+Torbj�rn T�rnqvist
+Claes Wikstr�m
+Tony Rogval
+Bj�rn Gustavsson
+Kenneth Lundin
+Jakob Cederlund
+Gordon Beaton
diff --git a/lib/erl_interface/Makefile b/lib/erl_interface/Makefile
new file mode 100644
index 0000000000..256b0309cd
--- /dev/null
+++ b/lib/erl_interface/Makefile
@@ -0,0 +1,32 @@
+#
+# %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%
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Common Macros
+# ----------------------------------------------------
+SUB_DIRECTORIES = src doc/src
+
+SPECIAL_TARGETS =
+
+# ----------------------------------------------------
+# Default Subdir Targets
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_subdir.mk
diff --git a/lib/erl_interface/aclocal.m4 b/lib/erl_interface/aclocal.m4
new file mode 120000
index 0000000000..151fd5ea5a
--- /dev/null
+++ b/lib/erl_interface/aclocal.m4
@@ -0,0 +1 @@
+../../erts/aclocal.m4 \ No newline at end of file
diff --git a/lib/erl_interface/configure.in b/lib/erl_interface/configure.in
new file mode 100644
index 0000000000..80b229c1c3
--- /dev/null
+++ b/lib/erl_interface/configure.in
@@ -0,0 +1,443 @@
+# -*- Autoconf -*-
+# %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%
+#
+# Process this file with autoconf to produce a configure script.
+# The starting point for this file was the output from 'autoscan'.
+
+# Strange, VxWorks HAVE_SENS not set here, see "ei_resolve.h"
+
+# Find the erl_interface version number and set m4 macro to it.
+# We do this because AC_INIT can't handle shell variables. Still broken.
+dnl m4_define(EI_VERSION,`grep EI_VSN ../vsn.mk | sed 's/^.*=[ ]*//'`)
+dnl m4_define(EI_VERSION,regexp(m4_include(VERSION),[version \([-.0-9A-Za-z]+\)],[\1]))
+
+AC_INIT()
+
+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
+
+dnl How to set srcdir absolute is taken from the GNU Emacs distribution
+#### Make srcdir absolute, if it isn't already. It's important to
+#### avoid running the path through pwd unnecessary, since pwd can
+#### give you automounter prefixes, which can go away.
+case "${srcdir}" in
+ /* ) ;;
+ . )
+ ## We may be able to use the $PWD environment variable to make this
+ ## absolute. But sometimes PWD is inaccurate.
+ ## Make sure CDPATH doesn't affect cd (in case PWD is relative).
+ CDPATH=
+ if test "${PWD}" != "" && test "`(cd ${PWD} ; sh -c pwd)`" = "`pwd`" ;
+ then
+ srcdir="$PWD"
+ else
+ srcdir="`(cd ${srcdir}; pwd)`"
+ fi
+ ;;
+ * ) srcdir="`(cd ${srcdir}; pwd)`" ;;
+esac
+
+AC_CONFIG_AUX_DIR([$srcdir/src/auxdir])
+
+if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then
+ AC_CANONICAL_HOST
+else
+ host_os=win32
+fi
+
+TARGET=$host
+AC_SUBST(TARGET)
+
+AC_CONFIG_HEADER([src/$host/config.h:src/auxdir/config.h.in])
+
+dnl ----------------------------------------------------------------------
+dnl Optional features
+dnl ----------------------------------------------------------------------
+
+AC_ARG_WITH(xcomp-conf,
+[ --with-xcompconf=PATH path to cross compilation configuration])
+if test "x$with_xcompconf" != "xno" -a "x$with_xcompconf" != "x" ; then
+ . $with_xcompconf
+fi
+
+# Use --disable-threads to force building single threaded libs even
+# if pthreads exists (for test purposes).
+AC_ARG_ENABLE(threads,
+[ --disable-threads use to only build single threaded libs],
+[ case "$enableval" in
+ no) threads_disabled=yes ;;
+ *) threads_disabled=no ;;
+ esac ],
+[ threads_disabled=no ])
+
+dnl ----------------------------------------------------------------------
+dnl Checks for programs
+dnl ----------------------------------------------------------------------
+
+AC_PROG_CC
+AC_PROG_CPP
+dnl AC_PROG_LIBTOOL
+AC_PROG_RANLIB
+if test "x$LD" = "x"; then
+ AC_CHECK_TOOL([LD],[ld],[ld])
+fi
+AC_SUBST(LD)
+
+AC_CHECK_SIZEOF(short, $erl_xcomp_short)
+AC_CHECK_SIZEOF(int, $erl_xcomp_int)
+AC_CHECK_SIZEOF(long, $erl_xcomp_long)
+AC_CHECK_SIZEOF(void *, $erl_xcomp_void_p)
+AC_CHECK_SIZEOF(long long, $erl_xcomp_long_long)
+
+if test $ac_cv_sizeof_void_p = 8; then
+ CFLAGS="$CFLAGS -DEI_64BIT"
+fi
+
+AC_CHECK_PROG(AR, ar, ar, false)
+if test "$ac_cv_prog_AR" = false; then
+ AC_MSG_ERROR([No 'ar' command found in PATH])
+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
+AC_SUBST(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
+
+# Checks for libraries.
+AC_CHECK_LIB([nsl], [gethostbyname])
+AC_CHECK_LIB([socket], [getpeername])
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h malloc.h netdb.h netinet/in.h stddef.h stdlib.h string.h sys/param.h sys/socket.h sys/select.h sys/time.h unistd.h sys/types.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+# fixme AC_C_CONST & AC_C_VOLATILE needed for Windows?
+dnl AC_C_CONST
+dnl AC_C_VOLATILE
+AC_TYPE_UID_T
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_MSG_CHECKING([for socklen_t usability])
+AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/socket.h>],
+[socklen_t mylen;],
+[AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_SOCKLEN_T)],
+[AC_MSG_RESULT(no)])
+
+# Checks for library functions.
+AC_FUNC_ALLOCA
+dnl AC_FUNC_FORK
+# FIXME check that this isn't set in normal cases
+AC_PROG_GCC_TRADITIONAL
+# Check if malloc(0) is ok
+dnl AC_FUNC_MALLOC
+dnl AC_FUNC_REALLOC
+AC_FUNC_MEMCMP
+dnl AC_FUNC_SELECT_ARGTYPES
+dnl AC_TYPE_SIGNAL
+dnl AC_FUNC_STRERROR_R
+dnl AC_FUNC_VPRINTF
+AC_CHECK_FUNCS([dup2 gethostbyaddr gethostbyname \
+ gethostbyaddr_r \
+ gethostbyname_r gethostname writev \
+ gethrtime gettimeofday inet_ntoa memchr memmove memset select \
+ socket strchr strerror strrchr strstr uname])
+AC_CHECK_FUNC(res_gethostbyname, [],
+ AC_CHECK_LIB(resolv, res_gethostbyname)
+)
+AC_CHECK_FUNC(clock_gettime, [],
+ AC_CHECK_LIB(rt, clock_gettime)
+)
+
+# ---------------------------------------------------------------------------
+# We don't link against libgmp except for "make check"
+# but linking will also tell us that it is >= 4.1
+# ---------------------------------------------------------------------------
+
+AC_ARG_WITH(gmp,
+[ --with-gmp=PATH specify location of GNU MP include and lib
+ --with-gmp use GNU MP (will search for it)])
+
+# We don't just want any GNU MP version, we want 4.1 or later
+# that contain the import/export functions we need.
+
+if test "x$with_gmp" = "xyes" ;then
+ for dir in /usr /usr/pkg /usr/local /usr/local/gmp /usr/lib/gmp /usr/gmp; do
+ AC_CHECK_HEADER($dir/include/gmp.h, ac_cv_gmp=yes, ac_cv_gmp=no)
+ if test $ac_cv_gmp = yes ; then
+ CFLAGS="$CFLAGS -I$dir/include -L$dir/lib"
+ AC_DEFINE(HAVE_GMP_H)
+ break
+ fi
+ done
+ if test $ac_cv_gmp = no ; then
+ AC_MSG_ERROR([No GNU MP installation found])
+ fi
+ AC_CHECK_LIB(gmp, __gmpz_export)
+ # FIXME return ERROR if no lib
+elif test "x$with_gmp" != "xno" -a -n "$with_gmp" ;then
+ # Option given with PATH to package
+ AC_MSG_CHECKING(for GNU MP)
+ if test ! -d "$with_gmp" ; then
+ AC_MSG_ERROR(Invalid path to option --with-gmp=PATH)
+ fi
+ AC_MSG_RESULT(yes)
+ CFLAGS="$CFLAGS -I$with_gmp/include -L$with_gmp/lib"
+ AC_DEFINE(HAVE_GMP_H)
+ AC_CHECK_LIB(gmp, __gmpz_export)
+ # FIXME return ERROR if no lib
+fi
+
+MIXED_CYGWIN=no
+
+AC_MSG_CHECKING(for mixed cygwin and native VC++ environment)
+if test "X$CC" = "Xcc.sh" -a "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_VC=yes
+ 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
+fi
+AC_SUBST(MIXED_CYGWIN_VC)
+
+AC_MSG_CHECKING(for mixed cygwin and native MinGW environment)
+if test "X$CC" = "Xcc.sh" -a "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
+ 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
+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)
+
+dnl
+dnl Threads
+dnl
+found_threads=no
+THR_LIBS=
+THR_DEFS=
+EI_THREADS="false"
+AC_SUBST(THR_LIBS)
+AC_SUBST(THR_DEFS)
+AC_SUBST(EI_THREADS)
+
+case "$threads_disabled" in
+ no)
+ AC_MSG_CHECKING([for native win32 threads])
+ if test "X$host_os" = "Xwin32"; then
+ THR_DEFS="-DWIN32_THREADS"
+ found_threads=yes
+ EI_THREADS="true"
+ AC_MSG_RESULT([yes])
+ AC_MSG_CHECKING([for __declspec(thread) usability])
+ if test "X$GCC" = "Xyes"; then
+ AC_MSG_RESULT([no])
+ else
+ THR_DEFS="$THR_DEFS -DUSE_DECLSPEC_THREAD"
+ AC_MSG_RESULT([yes])
+ fi
+ else
+ AC_MSG_RESULT(no)
+
+ dnl Check for POSIX threads
+
+ pthread_lib=""
+ AC_CHECK_LIB(pthread,
+ pthread_create,
+ [found_threads=yes
+ EI_THREADS="true"
+ THR_LIBS="-lpthread"
+ THR_DEFS="-D_REENTRANT -D_THREAD_SAFE -DPOSIX_THREADS"
+ pthread_lib=pthread])
+
+ # FreeBSD has pthreads in special c library, c_r
+ if test $found_threads = no; then
+ AC_CHECK_LIB(c_r,
+ pthread_create,
+ [found_threads=yes
+ EI_THREADS="true"
+ THR_LIBS="-lc_r"
+ THR_DEFS="-D_REENTRANT -D_THREAD_SAFE -DPOSIX_THREADS"
+ pthread_lib=c_r])
+ fi
+
+ if test "x$pthread_lib" != "x"; then
+ AC_CHECK_LIB($pthread_lib,pthread_atfork,AC_DEFINE(HAVE_PTHREAD_ATFORK))
+ AC_CHECK_HEADER(pthread.h, AC_DEFINE(HAVE_PTHREAD_H))
+ 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))
+ case $host_os in
+ solaris*)
+ THR_DEFS="$THR_DEFS -D_POSIX_PTHREAD_SEMANTICS";;
+ linux*)
+ dnl NPTL test stolen from $ERL_TOP/erts/aclocal.m4
+ AC_MSG_CHECKING(for Native POSIX Thread Library)
+ case `getconf GNU_LIBPTHREAD_VERSION 2>/dev/null` in
+ nptl*) nptl=yes;;
+ NPTL*) nptl=yes;;
+ *) nptl=no;;
+ esac
+ AC_MSG_RESULT($nptl)
+ if test $nptl = yes; then
+ need_nptl_incldir=no
+ AC_CHECK_HEADER(nptl/pthread.h, need_nptl_incldir=yes)
+ if test $need_nptl_incldir = yes; then
+ # Ahh...
+ nptl_path="$C_INCLUDE_PATH:$CPATH:/usr/local/include:/usr/include"
+ 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
+ fi
+ fi
+ ;;
+ yes)
+ # Threads disabled
+ ;;
+esac
+
+# ---------------------------------------------------------------------------
+# Warning flags to the C compiler
+# ---------------------------------------------------------------------------
+AC_SUBST(WFLAGS)
+
+if test "x$GCC" = xyes; then
+ 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'`
+ # GCC 3.3 and later supports C99 strict aliasing
+ # until all source is compliant with strict aliasing we disable it
+ case "$GCC_VERSION" in
+ 1*) ;;
+ 2*) ;;
+ 3.0*) ;;
+ 3.1*) ;;
+ 3.2*) ;;
+ *)
+ WFLAGS="$WFLAGS -fno-strict-aliasing";;
+ esac
+else
+ WFLAGS=""
+fi
+
+# ---------------------------------------------------------------------------
+# FIXME We want to use libtool but until then....
+# ---------------------------------------------------------------------------
+
+AC_SUBST(DED_CFLAGS)
+dnl AC_SUBST(DED_LD)
+dnl AC_SUBST(DED_LDFLAGS)
+
+if test "X$host" = "Xwin32"; then
+ DED_CFLAGS="$CFLAGS"
+else
+ case $host_os in
+ darwin*)
+ CFLAGS="$CFLAGS -no-cpp-precomp"
+ ;;
+ esac
+
+ if test "x$GCC" = xyes; then
+ DED_CFLAGS="$CFLAGS -fPIC"
+ else
+ DED_CFLAGS="$CFLAGS"
+ fi
+fi
+
+# ---------------------------------------------------------------------------
+# XXX
+# ---------------------------------------------------------------------------
+
+AC_OUTPUT(
+ src/$host/Makefile:src/Makefile.in
+ src/$host/eidefs.mk:src/eidefs.mk.in
+ )
diff --git a/lib/erl_interface/doc/html/.gitignore b/lib/erl_interface/doc/html/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/erl_interface/doc/html/.gitignore
diff --git a/lib/erl_interface/doc/man1/.gitignore b/lib/erl_interface/doc/man1/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/erl_interface/doc/man1/.gitignore
diff --git a/lib/erl_interface/doc/man3/.gitignore b/lib/erl_interface/doc/man3/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/erl_interface/doc/man3/.gitignore
diff --git a/lib/erl_interface/doc/pdf/.gitignore b/lib/erl_interface/doc/pdf/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/erl_interface/doc/pdf/.gitignore
diff --git a/lib/erl_interface/doc/src/Makefile b/lib/erl_interface/doc/src/Makefile
new file mode 100644
index 0000000000..e05b647cb2
--- /dev/null
+++ b/lib/erl_interface/doc/src/Makefile
@@ -0,0 +1,129 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1998-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%
+#
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN=$(EI_VSN)
+APPLICATION=erl_interface
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+XML_REF1_FILES = erl_call.xml
+XML_REF3_FILES = erl_connect.xml \
+ erl_error.xml \
+ erl_eterm.xml \
+ erl_format.xml \
+ erl_malloc.xml \
+ erl_marshal.xml \
+ erl_global.xml \
+ ei.xml \
+ ei_connect.xml \
+ registry.xml
+
+BOOK_FILES = book.xml
+XML_APPLICATION_FILES = ref_man.xml
+#ref_man_ei.xml ref_man_erl_interface.xml
+XML_PART_FILES = \
+ part.xml \
+ part_notes.xml \
+ part_notes_history.xml
+XML_CHAPTER_FILES = ei_users_guide.xml notes.xml notes_history.xml
+
+XML_FILES = $(XML_REF1_FILES) $(XML_REF3_FILES) $(BOOK_FILES) \
+ $(XML_APPLICATION_FILES) $(XML_PART_FILES) $(XML_CHAPTER_FILES)
+# ----------------------------------------------------
+
+HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
+ $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
+
+INFO_FILE = ../../info
+
+GIF_FILES =
+
+MAN1_FILES = $(XML_REF1_FILES:%.xml=$(MAN1DIR)/%.1)
+MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
+
+HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
+
+TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+XML_FLAGS +=
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+$(HTMLDIR)/%.gif: %.gif
+ $(INSTALL_DATA) $< $@
+
+docs: pdf html man
+
+$(TOP_PDF_FILE): $(XML_FILES)
+
+pdf: $(TOP_PDF_FILE)
+
+html: gifs $(HTML_REF_MAN_FILE)
+
+man: $(MAN1_FILES) $(MAN3_FILES)
+
+gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
+
+debug opt:
+
+clean clean_docs clean_tex:
+ rm -rf $(HTMLDIR)/*
+ rm -f $(MAN1DIR)/*
+ rm -f $(MAN3DIR)/*
+ rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+ rm -f errs core *~
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_docs_spec: docs
+ $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
+ $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
+ $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DATA) $(HTMLDIR)/* \
+ $(RELSYSDIR)/doc/html
+ $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
+ $(INSTALL_DIR) $(RELEASE_PATH)/man/man1
+ $(INSTALL_DATA) $(MAN1_FILES) $(RELEASE_PATH)/man/man1
+ $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
+ $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
+
+
+release_spec:
+
diff --git a/lib/erl_interface/doc/src/book.xml b/lib/erl_interface/doc/src/book.xml
new file mode 100644
index 0000000000..e911b6aa2b
--- /dev/null
+++ b/lib/erl_interface/doc/src/book.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE book SYSTEM "book.dtd">
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header titlestyle="normal">
+ <copyright>
+ <year>1998</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Erlang Interface</title>
+ <prepared>Gordon Beaton</prepared>
+ <docno></docno>
+ <date>1998-11-30</date>
+ <rev>1.2</rev>
+ <file>book.sgml</file>
+ </header>
+ <insidecover>
+ </insidecover>
+ <pagetext>Erlang Interface</pagetext>
+ <preamble>
+ <contents level="2"></contents>
+ </preamble>
+ <parts lift="no">
+ <xi:include href="part.xml"/>
+ </parts>
+ <applications>
+ <xi:include href="ref_man.xml"/>
+ </applications>
+ <releasenotes>
+ <xi:include href="notes.xml"/>
+ </releasenotes>
+ <listofterms></listofterms>
+ <index></index>
+</book>
+
diff --git a/lib/erl_interface/doc/src/ei.xml b/lib/erl_interface/doc/src/ei.xml
new file mode 100644
index 0000000000..2f65a8c375
--- /dev/null
+++ b/lib/erl_interface/doc/src/ei.xml
@@ -0,0 +1,728 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE cref SYSTEM "cref.dtd">
+
+<cref>
+ <header>
+ <copyright>
+ <year>2001</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>ei</title>
+ <prepared>Jakob Cederlund</prepared>
+ <responsible>Kent Boortz</responsible>
+ <docno>1</docno>
+ <approved>Kenneth Lundin</approved>
+ <checked></checked>
+ <date>2000-11-27</date>
+ <rev>PA1</rev>
+ <file>ei.sgml</file>
+ </header>
+ <lib>ei</lib>
+ <libsummary>routines for handling the erlang binary term format</libsummary>
+ <description>
+ <p>The library <c><![CDATA[ei]]></c> contains macros and functions to encode
+ and decode the erlang binary term format.</p>
+ <p>With <c><![CDATA[ei]]></c>, you can convert atoms, lists, numbers and
+ binaries to and from the binary format. This is useful when
+ writing port programs and drivers. <c><![CDATA[ei]]></c> uses a given
+ buffer, and no dynamic memory (with the exception of
+ <c><![CDATA[ei_decode_fun()]]></c>), and is often quite fast.</p>
+ <p>It also handles C-nodes, C-programs that talks erlang
+ distribution with erlang nodes (or other C-nodes) using the
+ erlang distribution format. The difference between <c><![CDATA[ei]]></c> and
+ <c><![CDATA[erl_interface]]></c> is that <c><![CDATA[ei]]></c> uses the binary format
+ directly when sending and receiving terms. It is also thread
+ safe, and using threads, one process can handle multiple
+ C-nodes. The <c><![CDATA[erl_interface]]></c> library is built on top of
+ <c><![CDATA[ei]]></c>, but of legacy reasons, it doesn't allow for multiple
+ C-nodes. In general, <c><![CDATA[ei]]></c> is the preferred way of doing
+ C-nodes.</p>
+ <p>The decode and encode functions use a buffer an index into the
+ buffer, which points at the point where to encode and
+ decode. The index is updated to point right after the term
+ encoded/decoded. No checking is done whether the term fits in
+ the buffer or not. If encoding goes outside the buffer, the
+ program may crash.</p>
+ <p>All functions takes two parameter, <c><![CDATA[buf]]></c> is a pointer to
+ the buffer where the binary data is / will be, <c><![CDATA[index]]></c> is a
+ pointer to an index into the buffer. This parameter will be
+ incremented with the size of the term decoded / encoded. The
+ data is thus at <c><![CDATA[buf[*index]]]></c> when an <c><![CDATA[ei]]></c> function is
+ called.</p>
+ <p>The encode functions all assumes that the <c><![CDATA[buf]]></c> and
+ <c><![CDATA[index]]></c> parameters points to a buffer big enough for the
+ data. To get the size of an encoded term, without encoding it,
+ pass <c><![CDATA[NULL]]></c> instead of a buffer pointer. The <c><![CDATA[index]]></c>
+ parameter will be incremented, but nothing will be encoded. This
+ is the way in <c><![CDATA[ei]]></c> to "preflight" term encoding.</p>
+ <p>There are also encode-functions that uses a dynamic buffer. It
+ is often more convenient to use these to encode data. All encode
+ functions comes in two versions: those starting with <c><![CDATA[ei_x]]></c>,
+ uses a dynamic buffer.</p>
+ <p>All functions return <c><![CDATA[0]]></c> if successful, and <c><![CDATA[-1]]></c> if
+ not. (For instance, if a term is not of the expected type, or
+ the data to decode is not a valid erlang term.)</p>
+ <p>Some of the decode-functions needs a preallocated buffer. This
+ buffer must be allocated big enough, and for non compound types
+ the <c><![CDATA[ei_get_type()]]></c>
+ function returns the size required (note that for strings an
+ extra byte is needed for the 0 string terminator).</p>
+ </description>
+ <funcs>
+ <func>
+ <name><ret>void</ret><nametext>ei_set_compat_rel(release_number)</nametext></name>
+ <fsummary>Set the ei library in compatibility mode</fsummary>
+ <type>
+ <v>unsigned release_number;</v>
+ </type>
+ <desc>
+ <marker id="ei_set_compat_rel"></marker>
+ <p>By default, the <c><![CDATA[ei]]></c> library is only guaranteed
+ to be compatible with other Erlang/OTP components from the same
+ release as the <c><![CDATA[ei]]></c> library itself. For example, <c><![CDATA[ei]]></c> from
+ the OTP R10 release is not compatible with an Erlang emulator
+ from the OTP R9 release by default.</p>
+ <p>A call to <c><![CDATA[ei_set_compat_rel(release_number)]]></c> sets the
+ <c><![CDATA[ei]]></c> library in compatibility mode of release
+ <c><![CDATA[release_number]]></c>. Valid range of <c><![CDATA[release_number]]></c>
+ is [7, current release]. This makes it possible to
+ communicate with Erlang/OTP components from earlier releases.</p>
+ <note>
+ <p>If this function is called, it may only be called once
+ and must be called before any other functions in the <c><![CDATA[ei]]></c>
+ library is called.</p>
+ </note>
+ <warning>
+ <p>You may run into trouble if this feature is used
+ carelessly. Always make sure that all communicating
+ components are either from the same Erlang/OTP release, or
+ from release X and release Y where all components
+ from release Y are in compatibility mode of release X.</p>
+ </warning>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_version(char *buf, int *index)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_version(ei_x_buff* x)</nametext></name>
+ <fsummary>Encode version</fsummary>
+ <desc>
+ <p>Encodes a version magic number for the binary format. Must
+ be the first token in a binary term.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_long(char *buf, int *index, long p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_long(ei_x_buff* x, long p)</nametext></name>
+ <fsummary>Encode integer</fsummary>
+ <desc>
+ <p>Encodes a long integer in the binary format.
+ Note that if the code is 64 bits the function ei_encode_long() is
+ exactly the same as ei_encode_longlong().</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_ulong(char *buf, int *index, unsigned long p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_ulong(ei_x_buff* x, unsigned long p)</nametext></name>
+ <fsummary>Encode unsigned integer</fsummary>
+ <desc>
+ <p>Encodes an unsigned long integer in the binary format.
+ Note that if the code is 64 bits the function ei_encode_ulong() is
+ exactly the same as ei_encode_ulonglong().</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_longlong(char *buf, int *index, long long p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_longlong(ei_x_buff* x, long long p)</nametext></name>
+ <fsummary>Encode integer</fsummary>
+ <desc>
+ <p>Encodes a GCC <c><![CDATA[long long]]></c> or Visual C++ <c><![CDATA[__int64]]></c> (64 bit)
+ integer in the binary format. Note that this function is missing
+ in the VxWorks port.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_ulonglong(char *buf, int *index, unsigned long long p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_ulonglong(ei_x_buff* x, unsigned long long p)</nametext></name>
+ <fsummary>Encode unsigned integer</fsummary>
+ <desc>
+ <p>Encodes a GCC <c><![CDATA[unsigned long long]]></c> or Visual C++ <c><![CDATA[unsigned __int64]]></c> (64 bit) integer in the binary format. Note that
+ this function is missing in the VxWorks port.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_bignum(char *buf, int *index, mpz_t obj)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_bignum(ei_x_buff *x, mpz_t obj)</nametext></name>
+ <fsummary>Encode an arbitrary precision integer</fsummary>
+ <desc>
+ <p>Encodes a GMP <c><![CDATA[mpz_t]]></c> integer to binary format.
+ To use this function the ei library needs to be configured and compiled
+ to use the GMP library. </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_double(char *buf, int *index, double p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_double(ei_x_buff* x, double p)</nametext></name>
+ <fsummary>Encode a double float</fsummary>
+ <desc>
+ <p>Encodes a double-precision (64 bit) floating point number in
+ the binary format.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_boolean(char *buf, int *index, int p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_boolean(ei_x_buff* x, int p)</nametext></name>
+ <fsummary>Encode a boolean</fsummary>
+ <desc>
+ <p>Encodes a boolean value, as the atom <c><![CDATA[true]]></c> if p is not
+ zero or <c><![CDATA[false]]></c> if p is zero.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_char(char *buf, int *index, char p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_char(ei_x_buff* x, char p)</nametext></name>
+ <fsummary>Encode an 8-bit integer between 0-255</fsummary>
+ <desc>
+ <p>Encodes a char (8-bit) as an integer between 0-255 in the binary format.
+ Note that for historical reasons the integer argument is of
+ type <c><![CDATA[char]]></c>. Your C code should consider the
+ given argument to be of type <c><![CDATA[unsigned char]]></c> even if
+ the C compilers and system may define <c><![CDATA[char]]></c> to be
+ signed.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_string(char *buf, int *index, const char *p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_encode_string_len(char *buf, int *index, const char *p, int len)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_string(ei_x_buff* x, const char *p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_string_len(ei_x_buff* x, const char* s, int len)</nametext></name>
+ <fsummary>Encode a string</fsummary>
+ <desc>
+ <p>Encodes a string in the binary format. (A string in erlang
+ is a list, but is encoded as a character array in the binary
+ format.) The string should be zero-terminated, except for
+ the <c><![CDATA[ei_x_encode_string_len()]]></c> function.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_atom(char *buf, int *index, const char *p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_encode_atom_len(char *buf, int *index, const char *p, int len)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_atom(ei_x_buff* x, const char *p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_atom_len(ei_x_buff* x, const char *p, int len)</nametext></name>
+ <fsummary>Encode an atom</fsummary>
+ <desc>
+ <p>Encodes an atom in the binary format. The <c><![CDATA[p]]></c> parameter
+ is the name of the atom. Only upto <c><![CDATA[MAXATOMLEN]]></c> bytes
+ are encoded. The name should be zero-terminated, except for
+ the <c><![CDATA[ei_x_encode_atom_len()]]></c> function.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_binary(char *buf, int *index, const void *p, long len)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_binary(ei_x_buff* x, const void *p, long len)</nametext></name>
+ <fsummary>Encode a binary</fsummary>
+ <desc>
+ <p>Encodes a binary in the binary format. The data is at
+ <c><![CDATA[p]]></c>, of <c><![CDATA[len]]></c> bytes length.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_pid(char *buf, int *index, const erlang_pid *p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_pid(ei_x_buff* x, const erlang_pid *p)</nametext></name>
+ <fsummary>Encode a pid</fsummary>
+ <desc>
+ <p>Encodes an erlang process identifier, pid, in the binary
+ format. The <c><![CDATA[p]]></c> parameter points to an
+ <c><![CDATA[erlang_pid]]></c> structure (which should have been obtained
+ earlier with <c><![CDATA[ei_decode_pid()]]></c>).</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_fun(char *buf, int *index, const erlang_fun *p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_fun(ei_x_buff* x, const erlang_fun* fun)</nametext></name>
+ <fsummary>Encode a fun</fsummary>
+ <desc>
+ <p>Encodes a fun in the binary format. The <c><![CDATA[p]]></c> parameter
+ points to an <c><![CDATA[erlang_fun]]></c> structure. The
+ <c><![CDATA[erlang_fun]]></c> is not freed automatically, the
+ <c><![CDATA[free_fun]]></c> should be called if the fun is not needed
+ after encoding.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_port(char *buf, int *index, const erlang_port *p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_port(ei_x_buff* x, const erlang_port *p)</nametext></name>
+ <fsummary>Encodes a port</fsummary>
+ <desc>
+ <p>Encodes an erlang port in the binary format. The <c><![CDATA[p]]></c>
+ parameter points to a <c><![CDATA[erlang_port]]></c> structure (which
+ should have been obtained earlier with
+ <c><![CDATA[ei_decode_port()]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_ref(char *buf, int *index, const erlang_ref *p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_ref(ei_x_buff* x, const erlang_ref *p)</nametext></name>
+ <fsummary>Encodes a ref</fsummary>
+ <desc>
+ <p>Encodes an erlang reference in the binary format. The
+ <c><![CDATA[p]]></c> parameter points to a <c><![CDATA[erlang_ref]]></c> structure
+ (which should have been obtained earlier with
+ <c><![CDATA[ei_decode_ref()]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_term(char *buf, int *index, void *t)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_term(ei_x_buff* x, void *t)</nametext></name>
+ <fsummary>Encode an <c><![CDATA[erl_interface]]></c>term</fsummary>
+ <desc>
+ <p>This function encodes an <c><![CDATA[ETERM]]></c>, as obtained from
+ <c><![CDATA[erl_interface]]></c>. The <c><![CDATA[t]]></c> parameter is actually an
+ <c><![CDATA[ETERM]]></c> pointer. This function doesn't free the
+ <c><![CDATA[ETERM]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_trace(char *buf, int *index, const erlang_trace *p)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_trace(ei_x_buff* x, const erlang_trace *p)</nametext></name>
+ <fsummary>Encode a trace token</fsummary>
+ <desc>
+ <p>This function encodes an erlang trace token in the binary
+ format. The <c><![CDATA[p]]></c> parameter points to a
+ <c><![CDATA[erlang_trace]]></c> structure (which should have been
+ obtained earlier with <c><![CDATA[ei_decode_trace()]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_tuple_header(char *buf, int *index, int arity)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_tuple_header(ei_x_buff* x, int arity)</nametext></name>
+ <fsummary>Encode a tuple</fsummary>
+ <desc>
+ <p>This function encodes a tuple header, with a specified
+ arity. The next <c><![CDATA[arity]]></c> terms encoded will be the
+ elements of the tuple. Tuples and lists are encoded
+ recursively, so that a tuple may contain another tuple or
+ list.</p>
+ <p>E.g. to encode the tuple <c><![CDATA[{a, {b, {}}}]]></c>:</p>
+ <pre>
+ei_encode_tuple_header(buf, &amp;i, 2);
+ei_encode_atom(buf, &amp;i, "a");
+ei_encode_tuple_header(buf, &amp;i, 2);
+ei_encode_atom(buf, &amp;i, "b");
+ei_encode_tuple_header(buf, &amp;i, 0);
+ </pre>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_list_header(char *buf, int *index, int arity)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_list_header(ei_x_buff* x, int arity)</nametext></name>
+ <fsummary>Encode a list</fsummary>
+ <desc>
+ <p>This function encodes a list header, with a specified
+ arity. The next <c><![CDATA[arity+1]]></c> terms are the elements
+ (actually it's <c><![CDATA[arity]]></c> cons cells) and the tail of the
+ list. Lists and tuples are encoded recursively, so that a
+ list may contain another list or tuple.</p>
+ <p>E.g. to encode the list <c><![CDATA[[c, d, [e | f]]]]></c>:</p>
+ <pre>
+ei_encode_list_header(buf, &amp;i, 3);
+ei_encode_atom(buf, &amp;i, "c");
+ei_encode_atom(buf, &amp;i, "d");
+ei_encode_list_header(buf, &amp;i, 1);
+ei_encode_atom(buf, &amp;i, "e");
+ei_encode_atom(buf, &amp;i, "f");
+ei_encode_empty_list(buf, &amp;i);
+ </pre>
+ <note>
+ <p>It may seem that there is no way to create a list without
+ knowing the number of elements in advance. But indeed
+ there is a way. Note that the list <c><![CDATA[[a, b, c]]]></c> can be
+ written as <c><![CDATA[[a | [b | [c]]]]]></c>. Using this, a list can
+ be written as conses.</p>
+ </note>
+ <p>To encode a list, without knowing the arity in advance:</p>
+ <pre>
+while (something()) {
+ ei_x_encode_list_header(&amp;x, 1);
+ ei_x_encode_ulong(&amp;x, i); /* just an example */
+}
+ei_x_encode_empty_list(&amp;x);
+ </pre>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_encode_empty_list(char* buf, int* index)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_encode_empty_list(ei_x_buff* x)</nametext></name>
+ <fsummary>Encode an empty list (<c><![CDATA[nil]]></c>)</fsummary>
+ <desc>
+ <p>This function encodes an empty list. It's often used at the
+ tail of a list.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_get_type(const char *buf, const int *index, int *type, int *size)</nametext></name>
+ <fsummary>Fetch the type and size of an encoded term</fsummary>
+ <desc>
+ <p>This function returns the type in <c><![CDATA[type]]></c> and size in
+ <c><![CDATA[size]]></c> of the encoded term.
+ For strings and atoms, size
+ is the number of characters <em>not</em> including the
+ terminating 0. For binaries, <c><![CDATA[size]]></c> is the number of
+ bytes. For lists and tuples, <c><![CDATA[size]]></c> is the arity of the
+ object. For other types, <c><![CDATA[size]]></c> is 0. In all cases,
+ <c><![CDATA[index]]></c> is left unchanged.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_version(const char *buf, int *index, int *version)</nametext></name>
+ <fsummary>Encode an empty list (<c><![CDATA[nil]]></c>)</fsummary>
+ <desc>
+ <p>This function decodes the version magic number for the
+ erlang binary term format. It must be the first token in a
+ binary term.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_long(const char *buf, int *index, long *p)</nametext></name>
+ <fsummary>Decode integer</fsummary>
+ <desc>
+ <p>This function decodes a long integer from the binary format.
+ Note that if the code is 64 bits the function ei_decode_long() is
+ exactly the same as ei_decode_longlong().</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_ulong(const char *buf, int *index, unsigned long *p)</nametext></name>
+ <fsummary>Decode unsigned integer</fsummary>
+ <desc>
+ <p>This function decodes an unsigned long integer from
+ the binary format.
+ Note that if the code is 64 bits the function ei_decode_ulong() is
+ exactly the same as ei_decode_ulonglong().</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_longlong(const char *buf, int *index, long long *p)</nametext></name>
+ <fsummary>Decode integer</fsummary>
+ <desc>
+ <p>This function decodes a GCC <c><![CDATA[long long]]></c> or Visual C++ <c><![CDATA[__int64]]></c>
+ (64 bit) integer from the binary format. Note that this
+ function is missing in the VxWorks port.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_ulonglong(const char *buf, int *index, unsigned long long *p)</nametext></name>
+ <fsummary>Decode unsigned integer</fsummary>
+ <desc>
+ <p>This function decodes a GCC <c><![CDATA[unsigned long long]]></c> or Visual C++
+ <c><![CDATA[unsigned __int64]]></c> (64 bit) integer from the binary format.
+ Note that this function is missing in the VxWorks port.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_bignum(const char *buf, int *index, mpz_t obj)</nametext></name>
+ <fsummary>Decode a GMP arbitrary precision integer</fsummary>
+ <desc>
+ <p>This function decodes an integer in the binary format to a GMP <c><![CDATA[mpz_t]]></c> integer.
+ To use this function the ei library needs to be configured and compiled
+ to use the GMP library. </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_double(const char *buf, int *index, double *p)</nametext></name>
+ <fsummary>Decode a double</fsummary>
+ <desc>
+ <p>This function decodes an double-precision (64 bit) floating
+ point number from the binary format.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_boolean(const char *buf, int *index, int *p)</nametext></name>
+ <fsummary>Decode a boolean</fsummary>
+ <desc>
+ <p>This function decodes a boolean value from the binary
+ format. A boolean is actually an atom, <c><![CDATA[true]]></c> decodes 1
+ and <c><![CDATA[false]]></c> decodes 0.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_char(const char *buf, int *index, char *p)</nametext></name>
+ <fsummary>Decode an 8-bit integer between 0-255</fsummary>
+ <desc>
+ <p>This function decodes a char (8-bit) integer between 0-255
+ from the binary format.
+ Note that for historical reasons the returned integer is of
+ type <c><![CDATA[char]]></c>. Your C code should consider the
+ returned value to be of type <c><![CDATA[unsigned char]]></c> even if
+ the C compilers and system may define <c><![CDATA[char]]></c> to be
+ signed.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_string(const char *buf, int *index, char *p)</nametext></name>
+ <fsummary>Decode a string</fsummary>
+ <desc>
+ <p>This function decodes a string from the binary format. A
+ string in erlang is a list of integers between 0 and
+ 255. Note that since the string is just a list, sometimes
+ lists are encoded as strings by <c><![CDATA[term_to_binary/1]]></c>,
+ even if it was not intended.</p>
+ <p>The string is copied to <c><![CDATA[p]]></c>, and enough space must be
+ allocated. The returned string is null terminated so you
+ need to add an extra byte to the memory requirement.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_atom(const char *buf, int *index, char *p)</nametext></name>
+ <fsummary>Decode an atom</fsummary>
+ <desc>
+ <p>This function decodes an atom from the binary format. The
+ name of the atom is placed at <c><![CDATA[p]]></c>. There can be at most
+ <c><![CDATA[MAXATOMLEN]]></c> bytes placed in the buffer.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_binary(const char *buf, int *index, void *p, long *len)</nametext></name>
+ <fsummary>Decode a binary</fsummary>
+ <desc>
+ <p>This function decodes a binary from the binary format. The
+ <c><![CDATA[len]]></c> parameter is set to the actual size of the
+ binary. Note that <c><![CDATA[ei_decode_binary()]]></c> assumes that there
+ are enough room for the binary. The size required can be
+ fetched by <c><![CDATA[ei_get_type()]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_fun(const char *buf, int *index, erlang_fun *p)</nametext></name>
+ <name><ret>void</ret><nametext>free_fun(erlang_fun* f)</nametext></name>
+ <fsummary>Decode a fun</fsummary>
+ <desc>
+ <p>This function decodes a fun from the binary format. The
+ <c><![CDATA[p]]></c> parameter should be NULL or point to an
+ <c><![CDATA[erlang_fun]]></c> structure. This is the only decode
+ function that allocates memory; when the <c><![CDATA[erlang_fun]]></c>
+ is no longer needed, it should be freed with
+ <c><![CDATA[free_fun]]></c>. (This has to do with the arbitrary size of
+ the environment for a fun.)</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_pid(const char *buf, int *index, erlang_pid *p)</nametext></name>
+ <fsummary>Decode a <c><![CDATA[pid]]></c></fsummary>
+ <desc>
+ <p>Decodes a pid, process identifier, from the binary format.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_port(const char *buf, int *index, erlang_port *p)</nametext></name>
+ <fsummary>Decode a port</fsummary>
+ <desc>
+ <p>This function decodes a port identifier from the binary
+ format.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_ref(const char *buf, int *index, erlang_ref *p)</nametext></name>
+ <fsummary>Decode a reference</fsummary>
+ <desc>
+ <p>This function decodes a reference from the binary format.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_trace(const char *buf, int *index, erlang_trace *p)</nametext></name>
+ <fsummary>Decode a trace token</fsummary>
+ <desc>
+ <p>Decodes an erlang trace token from the binary format.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_tuple_header(const char *buf, int *index, int *arity)</nametext></name>
+ <fsummary>Decode a tuple</fsummary>
+ <desc>
+ <p>This function decodes a tuple header, the number of elements
+ is returned in <c><![CDATA[arity]]></c>. The tuple elements follows in order in
+ the buffer.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_list_header(const char *buf, int *index, int *arity)</nametext></name>
+ <fsummary>Decode a list</fsummary>
+ <desc>
+ <p>This function decodes a list header from the binary
+ format. The number of elements is returned in
+ <c><![CDATA[arity]]></c>. The <c><![CDATA[arity+1]]></c> elements follows (the last
+ one is the tail of the list, normally an empty list.) If
+ <c><![CDATA[arity]]></c> is <c><![CDATA[0]]></c>, it's an empty list.</p>
+ <p>Note that lists are encoded as strings, if they consist
+ entirely of integers in the range 0..255. This function will
+ not decode such strings, use <c><![CDATA[ei_decode_string()]]></c>
+ instead.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_ei_term(const char* buf, int* index, ei_term* term)</nametext></name>
+ <fsummary>Decode a term, without prior knowledge of type</fsummary>
+ <desc>
+ <p>This function decodes any term, or at least tries to. If the
+ term pointed at by <c><![CDATA[*index]]></c> in <c><![CDATA[buf]]></c> fits in the
+ <c><![CDATA[term]]></c> union, it is decoded, and the appropriate field
+ in <c><![CDATA[term->value]]></c> is set, and <c><![CDATA[*index]]></c> is
+ incremented by the term size.</p>
+ <p>The function returns 0 on successful encoding, -1 on error,
+ and 1 if the term seems alright, but does not fit in the
+ <c><![CDATA[term]]></c> structure. If it returns 0, the <c><![CDATA[index]]></c>
+ will be incremented, and the <c><![CDATA[term]]></c> contains the
+ decoded term.</p>
+ <p>The <c><![CDATA[term]]></c> structure will contain the arity for a tuple
+ or list, size for a binary, string or atom. It will contains
+ a term if it's any of the following: integer, float, atom,
+ pid, port or ref.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_decode_term(const char *buf, int *index, void *t)</nametext></name>
+ <fsummary>Decode a <c><![CDATA[ETERM]]></c></fsummary>
+ <desc>
+ <p>This function decodes a term from the binary format. The
+ term is return in <c><![CDATA[t]]></c> as a <c><![CDATA[ETERM*]]></c>, so <c><![CDATA[t]]></c>
+ is actually an <c><![CDATA[ETERM**]]></c> (see
+ <c><![CDATA[erl_interface(3)]]></c>. The term should later be
+ deallocated.</p>
+ <p>Note that this function is located in the erl_interface
+ library.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_print_term(FILE* fp, const char* buf, int* index)</nametext></name>
+ <name><ret>int</ret><nametext>ei_s_print_term(char** s, const char* buf, int* index)</nametext></name>
+ <fsummary>Print a term in clear text</fsummary>
+ <desc>
+ <p>This function prints a term, in clear text, to the file
+ given by <c><![CDATA[fp]]></c>, or the buffer pointed to by <c><![CDATA[s]]></c>. It
+ tries to resemble the term printing in the erlang shell.</p>
+ <p>In <c><![CDATA[ei_s_print_term()]]></c>, the parameter <c><![CDATA[s]]></c> should
+ point to a dynamically (malloc) allocated string of
+ <c><![CDATA[BUFSIZ]]></c> bytes or a NULL pointer. The string may be
+ reallocated (and <c><![CDATA[*s]]></c> may be updated) by this function
+ if the result is more than <c><![CDATA[BUFSIZ]]></c> characters. The
+ string returned is zero-terminated.</p>
+ <p>The return value is the number of characters written to the
+ file or string, or -1 if <c><![CDATA[buf[index]]]></c> doesn't contain a
+ valid term. Unfortunately, I/O errors on <c><![CDATA[fp]]></c> is not
+ checked.</p>
+ <p>The argument <c><![CDATA[index]]></c> is updated, i.e. this function can
+ be viewed as en decode function that decodes a term into a
+ human readable format.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_x_format(ei_x_buff* x, const char* fmt, ...)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_format_wo_ver(ei_x_buff* x, const char *fmt, ... )</nametext></name>
+ <fsummary>Format a term from a format string and parameters.</fsummary>
+ <desc>
+ <p>Format a term, given as a string, to a buffer. This
+ functions works like a sprintf for erlang terms. The
+ <c><![CDATA[fmt]]></c> contains a format string, with arguments like
+ <c><![CDATA[~d]]></c>, to insert terms from variables. The following
+ formats are supported (with the C types given):</p>
+ <p></p>
+ <pre>
+~a - an atom, char*
+~s - a string, char*
+~i - an integer, int
+~l - a long integer, long int
+~u - a unsigned long integer, unsigned long int
+~f - a float, float
+~d - a double float, double float
+ </pre>
+ <p>For instance, to encode a tuple with some stuff:</p>
+ <pre>
+ei_x_format("{~a,~i,~d}", "numbers", 12, 3.14159)
+encodes the tuple {numbers,12,3.14159}
+ </pre>
+ <p>The <c><![CDATA[ei_x_format_wo_ver()]]></c> formats into a buffer, without
+ the initial version byte.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_x_new(ei_x_buff* x)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_new_with_version(ei_x_buff* x)</nametext></name>
+ <fsummary>Allocate a new buffer</fsummary>
+ <desc>
+ <p>This function allocates a new <c><![CDATA[ei_x_buff]]></c> buffer. The
+ fields of the structure pointed to by <c><![CDATA[x]]></c> parameter is
+ filled in, and a default buffer is allocated. The
+ <c><![CDATA[ei_x_new_with_version()]]></c> also puts an initial version
+ byte, that is used in the binary format. (So that
+ <c><![CDATA[ei_x_encode_version()]]></c> won't be needed.)</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_x_free(ei_x_buff* x)</nametext></name>
+ <fsummary>Frees a buffer</fsummary>
+ <desc>
+ <p>This function frees an <c><![CDATA[ei_x_buff]]></c> buffer. The memory
+ used by the buffer is returned to the OS.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_x_append(ei_x_buff* x, const ei_x_buff* x2)</nametext></name>
+ <name><ret>int</ret><nametext>ei_x_append_buf(ei_x_buff* x, const char* buf, int len)</nametext></name>
+ <fsummary>Appends a buffer at the end</fsummary>
+ <desc>
+ <p>These functions appends data at the end of the buffer <c><![CDATA[x]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_skip_term(const char* buf, int* index)</nametext></name>
+ <fsummary>skip a term</fsummary>
+ <desc>
+ <p>This function skips a term in the given buffer, it
+ recursively skips elements of lists and tuples, so that a
+ full term is skipped. This is a way to get the size of an
+ erlang term.</p>
+ <p><c><![CDATA[buf]]></c> is the buffer.</p>
+ <p><c><![CDATA[index]]></c> is updated to point right after the term in the
+ buffer.</p>
+ <note>
+ <p>This can be useful when you want to hold arbitrary
+ terms: just skip them and copy the binary term data to some
+ buffer.</p>
+ </note>
+ <p>The function returns <c><![CDATA[0]]></c> on success and <c><![CDATA[-1]]></c> on
+ failure.</p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>Debug Information</title>
+ <p>Some tips on what to check when the emulator doesn't seem to
+ receive the terms that you send.</p>
+ <list type="bulleted">
+ <item>be careful with the version header, use
+ <c><![CDATA[ei_x_new_with_version()]]></c> when appropriate</item>
+ <item>turn on distribution tracing on the erlang node</item>
+ <item>check the result codes from ei_decode_-calls</item>
+ </list>
+ </section>
+
+ <section>
+ <title>See Also</title>
+ <p>erl_interface(3)</p>
+ </section>
+</cref>
+
diff --git a/lib/erl_interface/doc/src/ei_connect.xml b/lib/erl_interface/doc/src/ei_connect.xml
new file mode 100644
index 0000000000..08e7b122c6
--- /dev/null
+++ b/lib/erl_interface/doc/src/ei_connect.xml
@@ -0,0 +1,639 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE cref SYSTEM "cref.dtd">
+
+<cref>
+ <header>
+ <copyright>
+ <year>2001</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>ei_connect</title>
+ <prepared>Jakob Cederlund</prepared>
+ <docno></docno>
+ <approved>?</approved>
+ <checked>?</checked>
+ <date>2001-09-01</date>
+ <rev>A</rev>
+ <file>ei_connect.sgml</file>
+ </header>
+ <lib>ei_connect</lib>
+ <libsummary>Communicate with distributed erlang</libsummary>
+ <description>
+ <p>This module enables C programs to communicate with erlang nodes,
+ using the erlang distribution over TCP/IP.</p>
+ <p>A C node appears to Erlang as a
+ <em>hidden node</em>.
+ That is, Erlang processes that know the name of the
+ C node are able to communicate with it in a normal manner, but
+ the node name will not appear in the listing provided by the
+ Erlang function <c><![CDATA[nodes/0]]></c>.</p>
+ <p>The environment variable <c><![CDATA[ERL_EPMD_PORT]]></c> can be used
+ to indicate which logical cluster a C node belongs to.</p>
+ </description>
+
+ <section>
+ <title>Timeout functions</title>
+ <p>Most functions appear in a version with the suffix
+ <c><![CDATA[_tmo]]></c> appended to the function name. Those function take
+ an additional argument, a timeout in <em>milliseconds</em>. The
+ semantics is this; for each communication primitive involved in
+ the operation, if the primitive does not complete within the time
+ specified, the function will return an error and
+ <c><![CDATA[erl_errno]]></c> will be set to <c><![CDATA[ETIMEDOUT]]></c>. With
+ communication primitive is ment an operation on the socket, like
+ <c><![CDATA[connect]]></c>, <c><![CDATA[accept]]></c>, <c><![CDATA[recv]]></c> or <c><![CDATA[send]]></c>.</p>
+ <p>Obviously the timeouts are for implementing fault tolerance,
+ not to keep hard realtime promises. The <c><![CDATA[_tmo]]></c> functions
+ are for detecting non-responsive peers and to avoid blocking on
+ socket operations. </p>
+ <p>A timeout value of <c><![CDATA[0]]></c> (zero), means that timeouts are
+ disabled. Calling a <c><![CDATA[_tmo]]></c>-function with the last argument as
+ <c><![CDATA[0]]></c> is therefore exactly the same thing as calling the
+ function without the <c><![CDATA[_tmo]]></c> suffix.</p>
+ <p>As with all other ei functions, you are <em>not</em> expected
+ to put the socket in non blocking mode yourself in the program. Every
+ use of non blocking mode is embedded inside the timeout
+ functions. The socket will always be back in blocking mode after
+ the operations are completed (regardless of the result). To
+ avoid problems, leave the socket options alone. Ei will handle
+ any socket options that need modification.</p>
+ <p>In all other senses, the <c><![CDATA[_tmo]]></c> functions inherit all
+ the return values and the semantics from the functions without
+ the <c><![CDATA[_tmo]]></c> suffix.</p>
+ </section>
+ <funcs>
+ <func>
+ <name><ret>int</ret><nametext>ei_connect_init(ei_cnode* ec, const char* this_node_name, const char *cookie, short creation)</nametext></name>
+ <name><ret>int</ret><nametext>ei_connect_xinit(ei_cnode* ec, const char *thishostname, const char *thisalivename, const char *thisnodename, Erl_IpAddr thisipaddr, const char *cookie, short creation)</nametext></name>
+ <fsummary>Initialize for a connection.</fsummary>
+ <desc>
+ <p>These function initializes the <c><![CDATA[ec]]></c> structure, to
+ identify the node name and cookie of the server. One of them
+ has to be called before other functions that works on the
+ type <c><![CDATA[ei_cnode]]></c> or a file descriptor associated with a
+ connection to another node are used.</p>
+ <p><c><![CDATA[ec]]></c> is a structure containing information about the
+ C-node. It is used in other <c><![CDATA[ei]]></c> functions for
+ connecting and receiving data.</p>
+ <p><c><![CDATA[this_node_name]]></c> is the registered name of the process
+ (the name before '@').</p>
+ <p><c><![CDATA[cookie]]></c> is the cookie for the node.</p>
+ <p><c><![CDATA[creation]]></c> identifies a specific instance of a C
+ node. It can help prevent the node from receiving messages
+ sent to an earlier process with the same registered name.</p>
+ <p><c><![CDATA[thishostname]]></c> is the name of the machine we're running
+ on. If long names are to be used, it should be fully
+ qualified (i.e. <c><![CDATA[durin.erix.ericsson.se]]></c> instead of
+ <c><![CDATA[durin]]></c>).</p>
+ <p><c><![CDATA[thisalivename]]></c> is the registered name of the process.</p>
+ <p><c><![CDATA[thisnodename]]></c> is the full name of the node,
+ i.e. <c><![CDATA[einode@durin]]></c>.</p>
+ <p><c><![CDATA[thispaddr]]></c> if the IP address of the host.</p>
+ <p>A C node acting as a server will be assigned a creation
+ number when it calls <c><![CDATA[ei_publish()]]></c>.</p>
+ <p>A connection is closed by simply closing the socket. Refer
+ to system documentation to close the socket gracefully (when
+ there are outgoing packets before close).</p>
+ <p>This function return a negative value indicating that an error
+ occurred.</p>
+ <p>Example 1:
+ </p>
+ <code type="none"><![CDATA[
+int n = 0;
+struct in_addr addr;
+ei_cnode ec;
+addr = inet_addr("150.236.14.75");
+if (ei_connect_xinit(&ec,
+ "chivas",
+ "madonna",
+ &addr;
+ "cookie...",
+ n++) < 0) {
+ fprintf(stderr,"ERROR when initializing: %d",erl_errno);
+ exit(-1);
+}
+ ]]></code>
+ <p>Example 2:
+ </p>
+ <code type="none"><![CDATA[
+if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) {
+ fprintf("ERROR when initializing: %d",erl_errno);
+ exit(-1);
+}
+ ]]></code>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_connect(ei_cnode* ec, char *nodename)</nametext></name>
+ <name><ret>int</ret><nametext>ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename)</nametext></name>
+ <fsummary>Establishe a connection to an Erlang node</fsummary>
+ <desc>
+ <p>These functions set up a connection to an Erlang node.</p>
+ <p><c><![CDATA[ei_xconnect()]]></c> requires the IP address of the remote
+ host and the alive name of the remote node
+ to be specified. <c><![CDATA[ei_connect()]]></c> provides an alternative
+ interface, and determines the information from the node name
+ provided.</p>
+ <p><c><![CDATA[addr]]></c> is the 32-bit IP address of the remote host.</p>
+ <p><c><![CDATA[alive]]></c> is the alivename of the remote node.</p>
+ <p><c><![CDATA[node]]></c> is the name of the remote node.</p>
+ <p>These functions return an open file descriptor on success, or
+ a negative value indicating that an error occurred --- in
+ which case they will set <c><![CDATA[erl_errno]]></c> to one of:</p>
+ <taglist>
+ <tag><c><![CDATA[EHOSTUNREACH]]></c></tag>
+ <item>The remote host <c><![CDATA[node]]></c> is unreachable</item>
+ <tag><c><![CDATA[ENOMEM]]></c></tag>
+ <item>No more memory available.</item>
+ <tag><c><![CDATA[EIO]]></c></tag>
+ <item>I/O error.</item>
+ </taglist>
+ <p>Additionally, <c><![CDATA[errno]]></c> values from
+ <c><![CDATA[socket]]></c><em>(2)</em> and <c><![CDATA[connect]]></c><em>(2)</em>
+ system calls may be propagated into <c><![CDATA[erl_errno]]></c>.</p>
+ <p>Example:</p>
+ <code type="none"><![CDATA[
+#define NODE "[email protected]"
+#define ALIVE "madonna"
+#define IP_ADDR "150.236.14.75"
+
+/*** Variant 1 ***/
+int fd = ei_connect(&ec, NODE);
+
+/*** Variant 2 ***/
+struct in_addr addr;
+addr = inet_addr(IP_ADDR);
+fd = ei_xconnect(&ec, &addr, ALIVE);
+ ]]></code>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned timeout_ms)</nametext></name>
+ <name><ret>int</ret><nametext>ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned timeout_ms)</nametext></name>
+ <fsummary>Establish a connection to an Erlang node with optional timeout</fsummary>
+ <desc>
+ <p>ei_connect and ei_xconnect with an optional timeout argument,
+ see the description at the beginning of this document.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_receive(int fd, unsigned char* bufp, int bufsize)</nametext></name>
+ <fsummary>Receive a message</fsummary>
+ <desc>
+ <p>This function receives a message consisting of a sequence
+ of bytes in the Erlang external format.</p>
+ <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection. It
+ is obtained from a previous <c><![CDATA[ei_connect]]></c> or
+ <c><![CDATA[ei_accept]]></c>.</p>
+ <p><c><![CDATA[bufp]]></c> is a buffer large enough to hold the expected
+ message. </p>
+ <p><c><![CDATA[bufsize]]></c> indicates the size of <c><![CDATA[bufp]]></c>.</p>
+ <p>If a <em>tick</em> occurs, i.e., the Erlang node on the
+ other end of the connection has polled this node to see if it
+ is still alive, the function will return <c><![CDATA[ERL_TICK]]></c> and
+ no message will be placed in the buffer. Also,
+ <c><![CDATA[erl_errno]]></c> will be set to <c><![CDATA[EAGAIN]]></c>.</p>
+ <p>On success, the message is placed in the specified buffer
+ and the function returns the number of bytes actually read. On
+ failure, the function returns <c><![CDATA[ERL_ERROR]]></c> and will set
+ <c><![CDATA[erl_errno]]></c> to one of:</p>
+ <taglist>
+ <tag><c><![CDATA[EAGAIN]]></c></tag>
+ <item>Temporary error: Try again.</item>
+ <tag><c><![CDATA[EMSGSIZE]]></c></tag>
+ <item>Buffer too small.</item>
+ <tag><c><![CDATA[EIO]]></c></tag>
+ <item>I/O error.</item>
+ </taglist>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_receive_tmo(int fd, unsigned char* bufp, int bufsize, unsigned timeout_ms)</nametext></name>
+ <fsummary>Receive a message with optional timeout</fsummary>
+ <desc>
+ <p>ei_receive with an optional timeout argument,
+ see the description at the beginning of this document.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_receive_msg(int fd, erlang_msg* msg, ei_x_buff* x)</nametext></name>
+ <name><ret>int</ret><nametext>ei_xreceive_msg(int fd, erlang_msg* msg, ei_x_buff* x)</nametext></name>
+ <fsummary>Receive a message</fsummary>
+ <desc>
+ <p>These functions receives a message to the buffer in
+ <c><![CDATA[x]]></c>. <c><![CDATA[ei_xreceive_msg]]></c> allows the buffer in
+ <c><![CDATA[x]]></c> to grow, but <c><![CDATA[ei_receive_msg]]></c> fails if the
+ message is bigger than the preallocated buffer in <c><![CDATA[x]]></c>.</p>
+ <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
+ <p><c><![CDATA[msg]]></c> is a pointer to an <c><![CDATA[erlang_msg]]></c> structure
+ and contains information on the message received.</p>
+ <p><c><![CDATA[x]]></c> is buffer obtained from <c><![CDATA[ei_x_new]]></c>.</p>
+ <p>On success, the function returns <c><![CDATA[ERL_MSG]]></c> and the
+ <c><![CDATA[msg]]></c> struct will be initialized. <c><![CDATA[erlang_msg]]></c>
+ is defined as follows:</p>
+ <code type="none"><![CDATA[
+typedef struct {
+ long msgtype;
+ erlang_pid from;
+ erlang_pid to;
+ char toname[MAXATOMLEN+1];
+ char cookie[MAXATOMLEN+1];
+ erlang_trace token;
+} erlang_msg;
+ ]]></code>
+ <p><c><![CDATA[msgtype]]></c> identifies the type of message, and is one of
+ <c><![CDATA[ERL_SEND]]></c>, <c><![CDATA[ERL_REG_SEND]]></c>, <c><![CDATA[ERL_LINK]]></c>,
+ <c><![CDATA[ERL_UNLINK]]></c> and <c><![CDATA[ERL_EXIT]]></c>.</p>
+ <p>If <c><![CDATA[msgtype]]></c> is <c><![CDATA[ERL_SEND]]></c> this indicates that an
+ ordinary send operation has taken place, and <c><![CDATA[msg->to]]></c>
+ contains the Pid of the recipient (the C-node). If
+ <c><![CDATA[type]]></c> is <c><![CDATA[ERL_REG_SEND]]></c> then a registered send
+ operation took place, and <c><![CDATA[msg->from]]></c> contains the Pid
+ of the sender.</p>
+ <p>If <c><![CDATA[msgtype]]></c> is <c><![CDATA[ERL_LINK]]></c> or <c><![CDATA[ERL_UNLINK]]></c>, then
+ <c><![CDATA[msg->to]]></c> and <c><![CDATA[msg->from]]></c> contain the pids of the
+ sender and recipient of the link or unlink.</p>
+ <p>If <c><![CDATA[msgtype]]></c> is <c><![CDATA[ERL_EXIT]]></c>, then this indicates that
+ a link has been broken. In this case, <c><![CDATA[msg->to]]></c> and
+ <c><![CDATA[msg->from]]></c> contain the pids of the linked processes.</p>
+ <p>The return value is the same as for <c><![CDATA[ei_receive]]></c>, see
+ above.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_receive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned imeout_ms)</nametext></name>
+ <name><ret>int</ret><nametext>ei_xreceive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned timeout_ms)</nametext></name>
+ <fsummary>Receive a message with optional timeout</fsummary>
+ <desc>
+ <p>ei_receive_msg and ei_xreceive_msg with an optional timeout argument,
+ see the description at the beginning of this document.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_receive_encoded(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen)</nametext></name>
+ <fsummary>Obsolete function for receiving a message</fsummary>
+ <desc>
+ <p>This function is retained for compatibility with code
+ generated by the interface compiler and with code following
+ examples in the same application.</p>
+ <p>In essence the function performs the same operation as
+ <c><![CDATA[ei_xreceive_msg]]></c>, but instead of using an ei_x_buff, the
+ function expects a pointer to a character pointer
+ (<c><![CDATA[mbufp]]></c>), where the character pointer should point to a
+ memory area allocated by <c><![CDATA[malloc]]></c>. The argument
+ <c><![CDATA[bufsz]]></c> should be a pointer to an integer containing the
+ exact size (in bytes) of the memory area. The function may
+ reallocate the memory area and will in such cases put the new
+ size in <c><![CDATA[*bufsz]]></c> and update <c><![CDATA[*mbufp]]></c>.</p>
+ <p>Furthermore the function returns either ERL_TICK or the
+ <c><![CDATA[msgtype]]></c> field of the <c><![CDATA[erlang_msg *msg]]></c>. The actual
+ length of the message is put in <c><![CDATA[*msglen]]></c>. On error it
+ will return a value <c><![CDATA[< 0]]></c>.</p>
+ <p>It is recommended to use ei_xreceive_msg instead when
+ possible, for the sake of readability. The function will
+ however be retained in the interface for compatibility and
+ will <em>not</em> be removed not be removed in future releases
+ without notice.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_receive_encoded_tmo(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen, unsigned timeout_ms)</nametext></name>
+ <fsummary>Obsolete function for receiving a message with timeout</fsummary>
+ <desc>
+ <p>ei_receive_encoded with an optional timeout argument,
+ see the description at the beginning of this document.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_send(int fd, erlang_pid* to, char* buf, int len)</nametext></name>
+ <fsummary>Send a message</fsummary>
+ <desc>
+ <p>This function sends an Erlang term to a process.</p>
+ <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
+ <p><c><![CDATA[to]]></c> is the Pid of the intended recipient of the
+ message.</p>
+ <p><c><![CDATA[buf]]></c> is the buffer containing the term in binary
+ format.</p>
+ <p><c><![CDATA[len]]></c> is the length of the message in bytes.</p>
+ <p>The function returns 0 if successful, otherwise -1, in the
+ latter case it will set <c><![CDATA[erl_errno]]></c> to <c><![CDATA[EIO]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_send_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms)</nametext></name>
+ <fsummary>Send a message with optional timeout</fsummary>
+ <desc>
+ <p>ei_send with an optional timeout argument,
+ see the description at the beginning of this document.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_send_encoded(int fd, erlang_pid* to, char* buf, int len)</nametext></name>
+ <fsummary>Obsolete function to send a message</fsummary>
+ <desc>
+ <p>Works exactly as ei_send, the alternative name retained for
+ backward compatibility. The function will <em>not</em> be
+ removed without notice.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_send_encoded_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned timeout_ms)</nametext></name>
+ <fsummary>Obsolete function to send a message with optional timeout</fsummary>
+ <desc>
+ <p>ei_send_encoded with an optional timeout argument,
+ see the description at the beginning of this document.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_send(ei_cnode* ec, int fd, char* server_name, char* buf, int len)</nametext></name>
+ <fsummary>Send a message to a registered name</fsummary>
+ <desc>
+ <p>This function sends an Erlang term to a registered process.
+ </p>
+ <p>This function sends an Erlang term to a process.</p>
+ <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
+ <p><c><![CDATA[server_name]]></c> is the registered name of the intended
+ recipient.</p>
+ <p><c><![CDATA[buf]]></c> is the buffer containing the term in binary
+ format.</p>
+ <p><c><![CDATA[len]]></c> is the length of the message in bytes.</p>
+ <p>The function returns 0 if successful, otherwise -1, in the
+ latter case it will set <c><![CDATA[erl_errno]]></c> to <c><![CDATA[EIO]]></c>.</p>
+ <p>Example, send the atom "ok" to the process "worker":</p>
+ <code type="none"><![CDATA[
+ei_x_buff x;
+ei_x_new_with_version(&x);
+ei_x_encode_atom(&x, "ok");
+if (ei_reg_send(&ec, fd, x.buff, x.index) < 0)
+ handle_error();
+ ]]></code>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_send_tmo(ei_cnode* ec, int fd, char* server_name, char* buf, int len, unsigned timeout_ms)</nametext></name>
+ <fsummary>Send a message to a registered name with optional timeout</fsummary>
+ <desc>
+ <p>ei_reg_send with an optional timeout argument,
+ see the description at the beginning of this document.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_send_reg_encoded(int fd, const erlang_pid *from, const char *to, const char *buf, int len)</nametext></name>
+ <fsummary>Obsolete function to send a message to a registered name</fsummary>
+ <desc>
+ <p>This function is retained for compatibility with code
+ generated by the interface compiler and with code following
+ examples in the same application.</p>
+ <p>The function works as <c><![CDATA[ei_reg_send]]></c> with one
+ exception. Instead of taking the <c><![CDATA[ei_cnode]]></c> as a first
+ argument, it takes a second argument, an <c><![CDATA[erlang_pid]]></c>
+ which should be the process identifier of the sending process
+ (in the erlang distribution protocol). </p>
+ <p>A suitable <c><![CDATA[erlang_pid]]></c> can be constructed from the
+ <c><![CDATA[ei_cnode]]></c> structure by the following example code:</p>
+ <code type="none"><![CDATA[
+ ei_cnode ec;
+ erlang_pid *self;
+ int fd; /* the connection fd */
+ ...
+ self = ei_self(&ec);
+ self->num = fd;
+ ]]></code>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_send_reg_encoded_tmo(int fd, const erlang_pid *from, const char *to, const char *buf, int len)</nametext></name>
+ <fsummary>Obsolete function to send a message to a registered name with timeout</fsummary>
+ <desc>
+ <p>ei_send_reg_encoded with an optional timeout argument,
+ see the description at the beginning of this document.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_rpc(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf, int argbuflen, ei_x_buff *x)</nametext></name>
+ <name><ret>int</ret><nametext>ei_rpc_to(ei_cnode *ec, int fd, char *mod, char *fun, const char *argbuf, int argbuflen)</nametext></name>
+ <name><ret>int</ret><nametext>ei_rpc_from(ei_cnode *ec, int fd, int timeout, erlang_msg *msg, ei_x_buff *x)</nametext></name>
+ <fsummary>Remote Procedure Call from C to Erlang</fsummary>
+ <desc>
+ <p>These functions support calling Erlang functions on remote nodes.
+ <c><![CDATA[ei_rpc_to()]]></c> sends an rpc request to a remote node and
+ <c><![CDATA[ei_rpc_from()]]></c> receives the results of such a call.
+ <c><![CDATA[ei_rpc()]]></c> combines the functionality of these two functions
+ by sending an rpc request and waiting for the results. See also
+ <c><![CDATA[rpc:call/4]]></c>. </p>
+ <p><c><![CDATA[ec]]></c> is the C-node structure previously initiated by a
+ call to <c><![CDATA[ei_connect_init()]]></c> or
+ <c><![CDATA[ei_connect_xinit()]]></c></p>
+ <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
+ <p><c><![CDATA[timeout]]></c> is the maximum time (in ms) to wait for
+ results. Specify <c><![CDATA[ERL_NO_TIMEOUT]]></c> to wait forever.
+ <c><![CDATA[ei_rpc()]]></c> will wait infinitely for the answer,
+ i.e. the call will never time out.</p>
+ <p><c><![CDATA[mod]]></c> is the name of the module containing the function
+ to be run on the remote node.</p>
+ <p><c><![CDATA[fun]]></c> is the name of the function to run.</p>
+ <p><c><![CDATA[argbuf]]></c> is a pointer to a buffer with an encoded
+ Erlang list, without a version magic number, containing the
+ arguments to be passed to the function.</p>
+ <p><c><![CDATA[argbuflen]]></c> is the length of the buffer containing the
+ encoded Erlang list.</p>
+ <p><c><![CDATA[msg]]></c> structure of type <c><![CDATA[erlang_msg]]></c> and contains
+ information on the message received. See <c><![CDATA[ei_receive_msg()]]></c>
+ for a description of the <c><![CDATA[erlang_msg]]></c> format.</p>
+ <p><c><![CDATA[x]]></c> points to the dynamic buffer that receives the
+ result. For for <c><![CDATA[ei_rpc()]]></c> this will be the result
+ without the version magic number. For <c><![CDATA[ei_rpc_from()]]></c>
+ the result will return a version magic number and a 2-tuple
+ <c><![CDATA[{rex,Reply}]]></c>.</p>
+ <p><c><![CDATA[ei_rpc()]]></c> returns the number of bytes in the result
+ on success and -1 on failure. <c><![CDATA[ei_rpc_from()]]></c> returns
+ number of bytes or one of <c><![CDATA[ERL_TICK]]></c>, <c><![CDATA[ERL_TIMEOUT]]></c>
+ and <c><![CDATA[ERL_ERROR]]></c> otherwise. When failing,
+ all three functions set <c><![CDATA[erl_errno]]></c> to one of:</p>
+ <taglist>
+ <tag><c><![CDATA[EIO]]></c></tag>
+ <item>I/O error.</item>
+ <tag><c><![CDATA[ETIMEDOUT]]></c></tag>
+ <item>Timeout expired.</item>
+ <tag><c><![CDATA[EAGAIN]]></c></tag>
+ <item>Temporary error: Try again.</item>
+ </taglist>
+ <p>Example, check to see if an erlang process is alive:</p>
+ <code type="none"><![CDATA[
+int index = 0, is_alive;
+ei_x_buff args, result;
+
+ei_x_new(&result);
+ei_x_new(&args);
+ei_x_encode_list_header(&args, 1);
+ei_x_encode_pid(&args, &check_pid);
+ei_x_encode_empty_list(&args);
+
+if (ei_rpc(&ec, fd, "erlang", "is_process_alive",
+ args.buff, args.index, &result) < 0)
+ handle_error();
+
+if (ei_decode_version(result.buff, &index) < 0
+ || ei_decode_bool(result.buff, &index, &is_alive) < 0)
+ handle_error();
+ ]]></code>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_publish(ei_cnode *ec, int port)</nametext></name>
+ <fsummary>Publish a node name</fsummary>
+ <desc>
+ <p>These functions are used by a server process to register
+ with the local name server <em>epmd</em>, thereby allowing
+ other processes to send messages by using the registered name.
+ Before calling either of these functions, the process should
+ have called <c><![CDATA[bind()]]></c> and <c><![CDATA[listen()]]></c> on an open socket.</p>
+ <p><c><![CDATA[ec]]></c> is the C-node structure.</p>
+ <p><c><![CDATA[port]]></c> is the local name to register, and should be the
+ same as the port number that was previously bound to the socket.</p>
+ <p><c><![CDATA[addr]]></c> is the 32-bit IP address of the local host.</p>
+ <p>To unregister with epmd, simply close the returned
+ descriptor. See also <c><![CDATA[ei_unpublish()]]></c>.</p>
+ <p>On success, the functions return a descriptor connecting the
+ calling process to epmd. On failure, they return -1 and set
+ <c><![CDATA[erl_errno]]></c> to <c><![CDATA[EIO]]></c>.</p>
+ <p>Additionally, <c><![CDATA[errno]]></c> values from <c><![CDATA[socket]]></c><em>(2)</em>
+ and <c><![CDATA[connect]]></c><em>(2)</em> system calls may be propagated
+ into <c><![CDATA[erl_errno]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_publish_tmo(ei_cnode *ec, int port, unsigned timeout_ms)</nametext></name>
+ <fsummary>Publish a node name with optional timeout</fsummary>
+ <desc>
+ <p>ei_publish with an optional timeout argument,
+ see the description at the beginning of this document.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_accept(ei_cnode *ec, int listensock, ErlConnect *conp)</nametext></name>
+ <fsummary>Accept a connection from another node</fsummary>
+ <desc>
+ <p>This function is used by a server process to accept a
+ connection from a client process.</p>
+ <p><c><![CDATA[ec]]></c> is the C-node structure.</p>
+ <p><c><![CDATA[listensock]]></c> is an open socket descriptor on which
+ <c><![CDATA[listen()]]></c> has previously been called.</p>
+ <p><c><![CDATA[conp]]></c> is a pointer to an <c><![CDATA[ErlConnect]]></c> struct,
+ described as follows:</p>
+ <code type="none"><![CDATA[
+typedef struct {
+ char ipadr[4];
+ char nodename[MAXNODELEN];
+} ErlConnect;
+ ]]></code>
+ <p>On success, <c><![CDATA[conp]]></c> is filled in with the address and
+ node name of the connecting client and a file descriptor is
+ returned. On failure, <c><![CDATA[ERL_ERROR]]></c> is returned and
+ <c><![CDATA[erl_errno]]></c> is set to <c><![CDATA[EIO]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_accept_tmo(ei_cnode *ec, int listensock, ErlConnect *conp, unsigned timeout_ms)</nametext></name>
+ <fsummary>Accept a connection from another node with optional timeout</fsummary>
+ <desc>
+ <p>ei_accept with an optional timeout argument,
+ see the description at the beginning of this document.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_unpublish(ei_cnode *ec)</nametext></name>
+ <fsummary>Unpublish a node name</fsummary>
+ <desc>
+ <p>This function can be called by a process to unregister a
+ specified node from epmd on the localhost. This may be
+ useful, for example, when epmd has not detected the failure of a
+ node, and will not allow the name to be reused. If you use this
+ function to unregister your own process, be sure to also close
+ the descriptor that was returned by <c><![CDATA[ei_publish()]]></c>.</p>
+ <note>
+ <p>Careless use of this function may have unpredictable
+ results, if the registered node is in fact still running.</p>
+ </note>
+ <p><c><![CDATA[ec]]></c> is the node structure of the node to unregister.</p>
+ <p>If the node was successfully unregistered from epmd, the
+ function returns 0. Otherwise, it returns -1 and sets
+ <c><![CDATA[erl_errno]]></c> is to <c><![CDATA[EIO]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_unpublish_tmo(ei_cnode *ec, unsigned timeout_ms)</nametext></name>
+ <fsummary>Unpublish a node name with optional timeout</fsummary>
+ <desc>
+ <p>ei_unpublish with an optional timeout argument,
+ see the description at the beginning of this document.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>const char *</ret><nametext>ei_thisnodename(ei_cnode *ec)</nametext></name>
+ <name><ret>const char *</ret><nametext>ei_thishostname(ei_cnode *ec)</nametext></name>
+ <name><ret>const char *</ret><nametext>ei_thisalivename(ei_cnode *ec)</nametext></name>
+ <fsummary>Retrieve some values</fsummary>
+ <desc>
+ <p>These functions can be used to retrieve information about
+ the C Node. These values are initially set with
+ <c><![CDATA[ei_connect_init()]]></c> or <c><![CDATA[ei_connect_xinit()]]></c>.</p>
+ <p>They simply fetches the appropriate field from the <c><![CDATA[ec]]></c>
+ structure. Read the field directly will probably be safe for
+ a long time, so these functions are not really needed.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>erlang_pid *</ret><nametext>ei_self(ei_cnode *ec)</nametext></name>
+ <fsummary>Retrieve the Pid of the C-node</fsummary>
+ <desc>
+ <p>This function retrieves the Pid of the C-node. Every C-node
+ has a (pseudo) pid used in <c><![CDATA[ei_send_reg]]></c>, <c><![CDATA[ei_rpc]]></c>
+ and others. This is contained in a field in the <c><![CDATA[ec]]></c>
+ structure. It will be safe for a long time to fetch this
+ field directly from the <c><![CDATA[ei_cnode]]></c> structure.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>struct hostent</ret><nametext>*ei_gethostbyname(const char *name)</nametext></name>
+ <name><ret>struct hostent</ret><nametext>*ei_gethostbyaddr(const char *addr, int len, int type)</nametext></name>
+ <name><ret>struct hostent</ret><nametext>*ei_gethostbyname_r(const char *name, struct hostent *hostp, char *buffer, int buflen, int *h_errnop)</nametext></name>
+ <name><ret>struct hostent</ret><nametext>*ei_gethostbyaddr_r(const char *addr, int length, int type, struct hostent *hostp, char *buffer, int buflen, int *h_errnop)</nametext></name>
+ <fsummary>Name lookup functions</fsummary>
+ <desc>
+ <p>These are convenience functions for some common name lookup functions.</p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>Debug Information</title>
+ <p>If a connection attempt fails, the following can be checked:</p>
+ <list type="bulleted">
+ <item><c><![CDATA[erl_errno]]></c></item>
+ <item>that the right cookie was used</item>
+ <item>that <em>epmd</em> is running</item>
+ <item>the remote Erlang node on the other side is running the
+ same version of Erlang as the <c><![CDATA[ei]]></c>
+ library.</item>
+ <item>the environment variable <c><![CDATA[ERL_EPMD_PORT]]></c>
+ is set correctly.</item>
+ </list>
+ </section>
+</cref>
+
diff --git a/lib/erl_interface/doc/src/ei_users_guide.xml b/lib/erl_interface/doc/src/ei_users_guide.xml
new file mode 100644
index 0000000000..5d18e356cb
--- /dev/null
+++ b/lib/erl_interface/doc/src/ei_users_guide.xml
@@ -0,0 +1,612 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2002</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>The El Library User's Guide</title>
+ <prepared>Kent Boortz</prepared>
+ <responsible>Kent Boortz</responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>ei_users_guide.xml</file>
+ </header>
+ <p>The Erl_Interface library contains functions. which help you
+ integrate programs written in C and Erlang. The functions in
+ Erl_Interface support the following:</p>
+ <list type="bulleted">
+ <item>manipulation of data represented as Erlang data types</item>
+ <item>conversion of data between C and Erlang formats</item>
+ <item>encoding and decoding of Erlang data types for transmission or storage</item>
+ <item>communication between C nodes and Erlang processes</item>
+ <item>backup and restore of C node state to and from Mnesia</item>
+ </list>
+ <p>In the following sections, these topics are described:</p>
+ <list type="bulleted">
+ <item>compiling your code for use with Erl_Interface</item>
+ <item>initializing Erl_Interface</item>
+ <item>encoding, decoding, and sending Erlang terms</item>
+ <item>building terms and patterns</item>
+ <item>pattern matching</item>
+ <item>connecting to a distributed Erlang node</item>
+ <item>using EPMD</item>
+ <item>sending and receiving Erlang messages</item>
+ <item>remote procedure calls</item>
+ <item>global names</item>
+ <item>the registry</item>
+ </list>
+
+ <section>
+ <title>Compiling and Linking Your Code</title>
+ <p>In order to use any of the Erl_Interface functions, include the
+ following lines in your code:</p>
+ <code type="none"><![CDATA[
+#include "erl_interface.h"
+#include "ei.h" ]]></code>
+ <p>Determine where the top directory of your OTP installation is. You
+ can find this out by starting Erlang and entering the following
+ command at the Eshell prompt:</p>
+ <code type="none"><![CDATA[
+Eshell V4.7.4 (abort with ^G)
+1> code:root_dir().
+/usr/local/otp ]]></code>
+ <p>To compile your code, make sure that your C compiler knows where
+ to find <c><![CDATA[erl_interface.h]]></c> by specifying an appropriate <c><![CDATA[-I]]></c>
+ argument on the command line, or by adding it to the <c><![CDATA[CFLAGS]]></c>
+ definition in your <c><![CDATA[Makefile]]></c>. The correct value for this path is
+ <c><![CDATA[$OTPROOT/lib/erl_interface]]></c><em>Vsn</em><c><![CDATA[/include]]></c>, where <c><![CDATA[$OTPROOT]]></c> is the path
+ reported by <c><![CDATA[code:root_dir/0]]></c> in the above example, and <em>Vsn</em> is
+ the version of the Erl_interface application, for example
+ <c><![CDATA[erl_interface-3.2.3]]></c></p>
+ <code type="none"><![CDATA[
+$ cc -c -I/usr/local/otp/lib/erl_interface-3.2.3/include myprog.c ]]></code>
+ <p>When linking, you will need to specify the path to
+ <c><![CDATA[liberl_interface.a]]></c> and <c><![CDATA[libei.a]]></c> with
+ <c><![CDATA[-L$OTPROOT/lib/erl_interface-3.2.3/lib]]></c>, and you will need to specify the
+ name of the libraries with <c><![CDATA[-lerl_interface -lei]]></c>. You can do
+ this on the command line or by adding the flags to the <c><![CDATA[LDFLAGS]]></c>
+ definition in your <c><![CDATA[Makefile]]></c>.</p>
+ <code type="none"><![CDATA[
+$ ld -L/usr/local/otp/lib/erl_interface-3.2.3/
+ lib myprog.o -lerl_interface -lei -o myprog ]]></code>
+ <p>Also, on some systems it may be necessary to link with some
+ additional libraries (e.g. <c><![CDATA[libnsl.a]]></c> and <c><![CDATA[libsocket.a]]></c> on
+ Solaris, or <c><![CDATA[wsock32.lib]]></c> on Windows) in order to use the
+ communication facilities of Erl_Interface.</p>
+ <p>If you are using Erl_Interface functions in a threaded
+ application based on POSIX threads or Solaris threads, then
+ Erl_Interface needs access to some of the synchronization
+ facilities in your threads package, and you will need to specify
+ additional compiler flags in order to indicate which of the packages
+ you are using. Define <c><![CDATA[_REENTRANT]]></c> and either <c><![CDATA[STHREADS]]></c> or
+ <c><![CDATA[PTHREADS]]></c>. The default is to use POSIX threads if
+ <c><![CDATA[_REENTRANT]]></c> is specified.</p>
+ </section>
+
+ <section>
+ <title>Initializing the erl_interface Library</title>
+ <p>Before calling any of the other Erl_Interface functions, you
+ must call <c><![CDATA[erl_init()]]></c> exactly once to initialize the library.
+ <c><![CDATA[erl_init()]]></c> takes two arguments, however the arguments are no
+ longer used by Erl_Interface, and should therefore be specified
+ as <c><![CDATA[erl_init(NULL,0)]]></c>.</p>
+ </section>
+
+ <section>
+ <title>Encoding, Decoding and Sending Erlang Terms</title>
+ <p>Data sent between distributed Erlang nodes is encoded in the
+ Erlang external format. Consequently, you have to encode and decode
+ Erlang terms into byte streams if you want to use the distribution
+ protocol to communicate between a C program and Erlang. </p>
+ <p>The Erl_Interface library supports this activity. It has a
+ number of C functions which create and manipulate Erlang data
+ structures. The library also contains an encode and a decode function.
+ The example below shows how to create and encode an Erlang tuple
+ <c><![CDATA[{tobbe,3928}]]></c>:</p>
+ <code type="none"><![CDATA[
+
+ETERM *arr[2], *tuple;
+char buf[BUFSIZ];
+int i;
+
+arr[0] = erl_mk_atom("tobbe");
+arr[1] = erl_mk_integer(3928);
+tuple = erl_mk_tuple(arr, 2);
+i = erl_encode(tuple, buf); ]]></code>
+ <p>Alternatively, you can use <c><![CDATA[erl_send()]]></c> and
+ <c><![CDATA[erl_receive_msg]]></c>, which handle the encoding and decoding of
+ messages transparently.</p>
+ <p>Refer to the Reference Manual for a complete description of the
+ following modules:</p>
+ <list type="bulleted">
+ <item>the <c><![CDATA[erl_eterm]]></c> module for creating Erlang terms</item>
+ <item>the <c><![CDATA[erl_marshal]]></c> module for encoding and decoding routines.</item>
+ </list>
+ </section>
+
+ <section>
+ <title>Building Terms and Patterns</title>
+ <p>The previous example can be simplified by using
+ <c><![CDATA[erl_format()]]></c> to create an Erlang term.</p>
+ <code type="none"><![CDATA[
+
+ETERM *ep;
+ep = erl_format("{~a,~i}", "tobbe", 3928); ]]></code>
+ <p>Refer to the Reference Manual, the <c><![CDATA[erl_format]]></c> module, for a
+ full description of the different format directives. The following
+ example is more complex:</p>
+ <code type="none"><![CDATA[
+
+ETERM *ep;
+ep = erl_format("[{name,~a},{age,~i},{data,~w}]",
+ "madonna",
+ 21,
+ erl_format("[{adr,~s,~i}]", "E-street", 42));
+erl_free_compound(ep); ]]></code>
+ <p>As in previous examples, it is your responsibility to free the
+ memory allocated for Erlang terms. In this example,
+ <c><![CDATA[erl_free_compound()]]></c> ensures that the complete term pointed to
+ by <c><![CDATA[ep]]></c> is released. This is necessary, because the pointer from
+ the second call to <c><![CDATA[erl_format()]]></c> is lost. </p>
+ <p>The following
+ example shows a slightly different solution:</p>
+ <code type="none"><![CDATA[
+
+ETERM *ep,*ep2;
+ep2 = erl_format("[{adr,~s,~i}]","E-street",42);
+ep = erl_format("[{name,~a},{age,~i},{data,~w}]",
+ "madonna", 21, ep2);
+erl_free_term(ep);
+erl_free_term(ep2); ]]></code>
+ <p>In this case, you free the two terms independently. The order in
+ which you free the terms <c><![CDATA[ep]]></c> and <c><![CDATA[ep2]]></c> is not important,
+ because the Erl_Interface library uses reference counting to
+ determine when it is safe to actually remove objects. </p>
+ <p>If you are not sure whether you have freed the terms properly, you
+ can use the following function to see the status of the fixed term
+ allocator:</p>
+ <code type="none"><![CDATA[
+long allocated, freed;
+
+erl_eterm_statistics(&allocated,&freed);
+printf("currently allocated blocks: %ld\n",allocated);
+printf("length of freelist: %ld\n",freed);
+
+/* really free the freelist */
+erl_eterm_release();
+ ]]></code>
+ <p>Refer to the Reference Manual, the <c><![CDATA[erl_malloc]]></c> module for more
+ information.</p>
+ </section>
+
+ <section>
+ <title>Pattern Matching</title>
+ <p>An Erlang pattern is a term that may contain unbound variables or
+ <c><![CDATA["do not care"]]></c> symbols. Such a pattern can be matched against a
+ term and, if the match is successful, any unbound variables in the
+ pattern will be bound as a side effect. The content of a bound
+ variable can then be retrieved.</p>
+ <code type="none"><![CDATA[
+
+ETERM *pattern;
+pattern = erl_format("{madonna,Age,_}"); ]]></code>
+ <p><c><![CDATA[erl_match()]]></c> is used to perform pattern matching. It takes a
+ pattern and a term and tries to match them. As a side effect any unbound
+ variables in the pattern will be bound. In the following example, we
+ create a pattern with a variable <em>Age</em> which appears at two
+ positions in the tuple. The pattern match is performed as follows:</p>
+ <list type="ordered">
+ <item><c><![CDATA[erl_match()]]></c> will bind the contents of
+ <em>Age</em> to <em>21</em> the first time it reaches the variable</item>
+ <item>the second occurrence of <em>Age</em> will cause a test for
+ equality between the terms since <em>Age</em> is already bound to
+ <em>21</em>. Since <em>Age</em> is bound to 21, the equality test will
+ succeed and the match continues until the end of the pattern.</item>
+ <item>if the end of the pattern is reached, the match succeeds and you
+ can retrieve the contents of the variable</item>
+ </list>
+ <code type="none"><![CDATA[
+ETERM *pattern,*term;
+pattern = erl_format("{madonna,Age,Age}");
+term = erl_format("{madonna,21,21}");
+if (erl_match(pattern, term)) {
+ fprintf(stderr, "Yes, they matched: Age = ");
+ ep = erl_var_content(pattern, "Age");
+ erl_print_term(stderr, ep);
+ fprintf(stderr,"\n");
+ erl_free_term(ep);
+}
+erl_free_term(pattern);
+erl_free_term(term); ]]></code>
+ <p>Refer to the Reference Manual, the <c><![CDATA[erl_match()]]></c> function for
+ more information.</p>
+ </section>
+
+ <section>
+ <title>Connecting to a Distributed Erlang Node</title>
+ <p>In order to connect to a distributed Erlang node you need to first
+ initialize the connection routine with <c><![CDATA[erl_connect_init()]]></c>,
+ which stores information such as the host name, node name, and IP
+ address for later use:</p>
+ <code type="none"><![CDATA[
+int identification_number = 99;
+int creation=1;
+char *cookie="a secret cookie string"; /* An example */
+erl_connect_init(identification_number, cookie, creation); ]]></code>
+ <p>Refer to the Reference Manual, the <c><![CDATA[erl_connect]]></c> module for more information.</p>
+ <p>After initialization, you set up the connection to the Erlang node.
+ Use <c><![CDATA[erl_connect()]]></c> to specify the Erlang node you want to
+ connect to. The following example sets up the connection and should
+ result in a valid socket file descriptor:</p>
+ <code type="none"><![CDATA[
+int sockfd;
+char *nodename="[email protected]"; /* An example */
+if ((sockfd = erl_connect(nodename)) < 0)
+ erl_err_quit("ERROR: erl_connect failed"); ]]></code>
+ <p><c><![CDATA[erl_err_quit()]]></c> prints the specified string and terminates
+ the program. Refer to the Reference Manual, the <c><![CDATA[erl_error()]]></c>
+ function for more information.</p>
+ </section>
+
+ <section>
+ <title>Using EPMD</title>
+ <p><c><![CDATA[Epmd]]></c> is the Erlang Port Mapper Daemon. Distributed Erlang nodes
+ register with <c><![CDATA[epmd]]></c> on the localhost to indicate to other nodes that
+ they exist and can accept connections. <c><![CDATA[Epmd]]></c> maintains a register of
+ node and port number information, and when a node wishes to connect to
+ another node, it first contacts <c><![CDATA[epmd]]></c> in order to find out the correct
+ port number to connect to.</p>
+ <p>When you use <c><![CDATA[erl_connect()]]></c> to connect to an Erlang node, a
+ connection is first made to <c><![CDATA[epmd]]></c> and, if the node is known, a
+ connection is then made to the Erlang node.</p>
+ <p>C nodes can also register themselves with <c><![CDATA[epmd]]></c> if they want other
+ nodes in the system to be able to find and connect to them.</p>
+ <p>Before registering with <c><![CDATA[epmd]]></c>, you need to first create a listen socket
+ and bind it to a port. Then:</p>
+ <code type="none"><![CDATA[
+int pub;
+
+pub = erl_publish(port); ]]></code>
+ <p><c><![CDATA[pub]]></c> is a file descriptor now connected to <c><![CDATA[epmd]]></c>. <c><![CDATA[Epmd]]></c>
+ monitors the other end of the connection, and if it detects that the
+ connection has been closed, the node will be unregistered. So, if you
+ explicitly close the descriptor or if your node fails, it will be
+ unregistered from <c><![CDATA[epmd]]></c>.</p>
+ <p>Be aware that on some systems (such as VxWorks), a failed node will
+ not be detected by this mechanism since the operating system does not
+ automatically close descriptors that were left open when the node
+ failed. If a node has failed in this way, <c><![CDATA[epmd]]></c> will prevent you from
+ registering a new node with the old name, since it thinks that the old
+ name is still in use. In this case, you must unregister the name
+ explicitly:</p>
+ <code type="none"><![CDATA[
+erl_unpublish(node); ]]></code>
+ <p>This will cause <c><![CDATA[epmd]]></c> to close the connection from the far end. Note
+ that if the name was in fact still in use by a node, the results of
+ this operation are unpredictable. Also, doing this does not cause the
+ local end of the connection to close, so resources may be consumed.</p>
+ </section>
+
+ <section>
+ <title>Sending and Receiving Erlang Messages</title>
+ <p>Use one of the following two functions to send messages:</p>
+ <list type="bulleted">
+ <item><c><![CDATA[erl_send()]]></c></item>
+ <item><c><![CDATA[erl_reg_send()]]></c></item>
+ </list>
+ <p>As in Erlang, it is possible to send messages to a
+ <em>Pid</em> or to a registered name. It is easier to send a
+ message to a registered name because it avoids the problem of finding
+ a suitable <em>Pid</em>.</p>
+ <p>Use one of the following two functions to receive messages:</p>
+ <list type="bulleted">
+ <item><c><![CDATA[erl_receive()]]></c></item>
+ <item><c><![CDATA[erl_receive_msg()]]></c></item>
+ </list>
+ <p><c><![CDATA[erl_receive()]]></c> receives the message into a buffer, while
+ <c><![CDATA[erl_receive_msg()]]></c> decodes the message into an Erlang term. </p>
+
+ <section>
+ <title>Example of Sending Messages</title>
+ <p>In the following example, <c><![CDATA[{Pid, hello_world}]]></c> is
+ sent to a registered process <c><![CDATA[my_server]]></c>. The message is encoded
+ by <c><![CDATA[erl_send()]]></c>:</p>
+ <code type="none"><![CDATA[
+extern const char *erl_thisnodename(void);
+extern short erl_thiscreation(void);
+#define SELF(fd) erl_mk_pid(erl_thisnodename(),fd,0,erl_thiscreation())
+ETERM *arr[2], *emsg;
+int sockfd, creation=1;
+
+arr[0] = SELF(sockfd);
+arr[1] = erl_mk_atom("Hello world");
+emsg = erl_mk_tuple(arr, 2);
+
+erl_reg_send(sockfd, "my_server", emsg);
+erl_free_term(emsg); ]]></code>
+ <p>The first element of the tuple that is sent is your own
+ <em>Pid</em>. This enables <c><![CDATA[my_server]]></c> to reply. Refer to the
+ Reference Manual, the <c><![CDATA[erl_connect]]></c> module for more information
+ about send primitives.</p>
+ </section>
+
+ <section>
+ <title>Example of Receiving Messages</title>
+ <p>In this example <c><![CDATA[{Pid, Something}]]></c> is received. The
+ received Pid is then used to return <c><![CDATA[{goodbye,Pid}]]></c></p>
+ <code type="none"><![CDATA[
+ETERM *arr[2], *answer;
+int sockfd,rc;
+char buf[BUFSIZE];
+ErlMessage emsg;
+
+if ((rc = erl_receive_msg(sockfd , buf, BUFSIZE, &emsg)) == ERL_MSG) {
+ arr[0] = erl_mk_atom("goodbye");
+ arr[1] = erl_element(1, emsg.msg);
+ answer = erl_mk_tuple(arr, 2);
+ erl_send(sockfd, arr[1], answer);
+ erl_free_term(answer);
+ erl_free_term(emsg.msg);
+ erl_free_term(emsg.to);
+} ]]></code>
+ <p>In order to provide robustness, a distributed Erlang node
+ occasionally polls all its connected neighbours in an attempt to
+ detect failed nodes or communication links. A node which receives such
+ a message is expected to respond immediately with an <c><![CDATA[ERL_TICK]]></c> message.
+ This is done automatically by <c><![CDATA[erl_receive()]]></c>, however when this
+ has occurred <c><![CDATA[erl_receive]]></c> returns <c><![CDATA[ERL_TICK]]></c> to the caller
+ without storing a message into the <c><![CDATA[ErlMessage]]></c> structure.</p>
+ <p>When a message has been received, it is the caller's responsibility
+ to free the received message <c><![CDATA[emsg.msg]]></c> as well as <c><![CDATA[emsg.to]]></c>
+ or <c><![CDATA[emsg.from]]></c>, depending on the type of message received.</p>
+ <p>Refer to the Reference Manual for additional information about the
+ following modules:</p>
+ <list type="bulleted">
+ <item><c><![CDATA[erl_connect]]></c></item>
+ <item><c><![CDATA[erl_eterm]]></c>.</item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Remote Procedure Calls</title>
+ <p>An Erlang node acting as a client to another Erlang node
+ typically sends a request and waits for a reply. Such a request is
+ included in a function call at a remote node and is called a remote
+ procedure call. The following example shows how the
+ Erl_Interface library supports remote procedure calls:</p>
+ <code type="none"><![CDATA[
+
+char modname[]=THE_MODNAME;
+ETERM *reply,*ep;
+ep = erl_format("[~a,[]]", modname);
+if (!(reply = erl_rpc(fd, "c", "c", ep)))
+ erl_err_msg("<ERROR> when compiling file: %s.erl !\n", modname);
+erl_free_term(ep);
+ep = erl_format("{ok,_}");
+if (!erl_match(ep, reply))
+ erl_err_msg("<ERROR> compiler errors !\n");
+erl_free_term(ep);
+erl_free_term(reply); ]]></code>
+ <p><c><![CDATA[c:c/1]]></c> is called to compile the specified module on the
+ remote node. <c><![CDATA[erl_match()]]></c> checks that the compilation was
+ successful by testing for the expected <c><![CDATA[ok]]></c>.</p>
+ <p>Refer to the Reference Manual, the <c><![CDATA[erl_connect]]></c> module for
+ more information about <c><![CDATA[erl_rpc()]]></c>, and its companions
+ <c><![CDATA[erl_rpc_to()]]></c> and <c><![CDATA[erl_rpc_from()]]></c>.</p>
+ </section>
+
+ <section>
+ <title>Using Global Names</title>
+ <p>A C node has access to names registered through the Erlang Global
+ module. Names can be looked up, allowing the C node to send messages
+ to named Erlang services. C nodes can also register global names,
+ allowing them to provide named services to Erlang processes or other C
+ nodes. </p>
+ <p>Erl_Interface does not provide a native implementation of the global
+ service. Instead it uses the global services provided by a "nearby"
+ Erlang node. In order to use the services described in this section,
+ it is necessary to first open a connection to an Erlang node.</p>
+ <p>To see what names there are:</p>
+ <code type="none"><![CDATA[
+char **names;
+int count;
+int i;
+
+names = erl_global_names(fd,&count);
+
+if (names)
+ for (i=0; i<count; i++)
+ printf("%s\n",names[i]);
+
+free(names); ]]></code>
+ <p><c><![CDATA[erl_global_names()]]></c> allocates and returns a buffer containing
+ all the names known to global. <c><![CDATA[count]]></c> will be initialized to
+ indicate how many names are in the array. The array of strings in
+ names is terminated by a NULL pointer, so it is not necessary to use
+ <c><![CDATA[count]]></c> to determine when the last name is reached.</p>
+ <p>It is the caller's responsibility to free the array.
+ <c><![CDATA[erl_global_names()]]></c> allocates the array and all of the strings
+ using a single call to <c><![CDATA[malloc()]]></c>, so <c><![CDATA[free(names)]]></c> is all
+ that is necessary.</p>
+ <p>To look up one of the names:</p>
+ <code type="none"><![CDATA[
+ETERM *pid;
+char node[256];
+
+pid = erl_global_whereis(fd,"schedule",node); ]]></code>
+ <p>If <c><![CDATA["schedule"]]></c> is known to global, an Erlang pid is returned
+ that can be used to send messages to the schedule service.
+ Additionally, <c><![CDATA[node]]></c> will be initialized to contain the name of
+ the node where the service is registered, so that you can make a
+ connection to it by simply passing the variable to <c><![CDATA[erl_connect()]]></c>.</p>
+ <p>Before registering a name, you should already have registered your
+ port number with <c><![CDATA[epmd]]></c>. This is not strictly necessary, but if you
+ neglect to do so, then other nodes wishing to communicate with your
+ service will be unable to find or connect to your process.</p>
+ <p>Create a pid that Erlang processes can use to communicate with your
+ service:</p>
+ <code type="none"><![CDATA[
+ETERM *pid;
+
+pid = erl_mk_pid(thisnode,14,0,0);
+erl_global_register(fd,servicename,pid); ]]></code>
+ <p>After registering the name, you should use <c><![CDATA[erl_accept()]]></c> to wait for
+ incoming connections.</p>
+ <p>Do not forget to free <c><![CDATA[pid]]></c> later with <c><![CDATA[erl_free_term()]]></c>!</p>
+ <p>To unregister a name:</p>
+ <code type="none"><![CDATA[
+erl_global_unregister(fd,servicename); ]]></code>
+ </section>
+
+ <section>
+ <title>The Registry</title>
+ <p>This section describes the use of the registry, a simple mechanism
+ for storing key-value pairs in a C-node, as well as backing them up or
+ restoring them from a Mnesia table on an Erlang node. More detailed
+ information about the individual API functions can be found in the
+ Reference Manual.</p>
+ <p>Keys are strings, i.e. 0-terminated arrays of characters, and values
+ are arbitrary objects. Although integers and floating point numbers
+ are treated specially by the registry, you can store strings or binary
+ objects of any type as pointers.</p>
+ <p>To start, you need to open a registry:</p>
+ <code type="none"><![CDATA[
+ei_reg *reg;
+
+reg = ei_reg_open(45); ]]></code>
+ <p>The number 45 in the example indicates the approximate number of
+ objects that you expect to store in the registry. Internally the
+ registry uses hash tables with collision chaining, so there is no
+ absolute upper limit on the number of objects that the registry can
+ contain, but if performance or memory usage are important, then you
+ should choose a number accordingly. The registry can be resized later.</p>
+ <p>You can open as many registries as you like (if memory permits).</p>
+ <p>Objects are stored and retrieved through set and get functions. In
+ the following examples you see how to store integers, floats, strings
+ and arbitrary binary objects:</p>
+ <code type="none"><![CDATA[
+struct bonk *b = malloc(sizeof(*b));
+char *name = malloc(7);
+
+ei_reg_setival(reg,"age",29);
+ei_reg_setfval(reg,"height",1.85);
+
+strcpy(name,"Martin");
+ei_reg_setsval(reg,"name",name);
+
+b->l = 42;
+b->m = 12;
+ei_reg_setpval(reg,"jox",b,sizeof(*b)); ]]></code>
+ <p>If you attempt to store an object in the registry and there is an
+ existing object with the same key, the new value will replace the old
+ one. This is done regardless of whether the new object and the old one
+ have the same type, so you can, for example, replace a string with an
+ integer. If the existing value is a string or binary, it will be freed
+ before the new value is assigned.</p>
+ <p>Stored values are retrieved from the registry as follows:</p>
+ <code type="none"><![CDATA[
+long i;
+double f;
+char *s;
+struct bonk *b;
+int size;
+
+i = ei_reg_getival(reg,"age");
+f = ei_reg_getfval(reg,"height");
+s = ei_reg_getsval(reg,"name");
+b = ei_reg_getpval(reg,"jox",&size); ]]></code>
+ <p>In all of the above examples, the object must exist and it must be of
+ the right type for the specified operation. If you do not know the
+ type of a given object, you can ask:</p>
+ <code type="none"><![CDATA[
+struct ei_reg_stat buf;
+
+ei_reg_stat(reg,"name",&buf); ]]></code>
+ <p>Buf will be initialized to contain object attributes.</p>
+ <p>Objects can be removed from the registry:</p>
+ <code type="none"><![CDATA[
+ei_reg_delete(reg,"name"); ]]></code>
+ <p>When you are finished with a registry, close it to remove all the
+ objects and free the memory back to the system:</p>
+ <code type="none"><![CDATA[
+ei_reg_close(reg); ]]></code>
+
+ <section>
+ <title>Backing Up the Registry to Mnesia</title>
+ <p>The contents of a registry can be backed up to Mnesia on a "nearby"
+ Erlang node. You need to provide an open connection to the Erlang node
+ (see <c><![CDATA[erl_connect()]]></c>). Also, Mnesia 3.0 or later must be running
+ on the Erlang node before the backup is initiated:</p>
+ <code type="none"><![CDATA[
+ei_reg_dump(fd, reg, "mtab", dumpflags); ]]></code>
+ <p>The example above will backup the contents of the registry to the
+ specified Mnesia table <c><![CDATA["mtab"]]></c>. Once a registry has been backed
+ up to Mnesia in this manner, additional backups will only affect
+ objects that have been modified since the most recent backup, i.e.
+ objects that have been created, changed or deleted. The backup
+ operation is done as a single atomic transaction, so that the entire
+ backup will be performed or none of it will.</p>
+ <p>In the same manner, a registry can be restored from a Mnesia table:</p>
+ <code type="none"><![CDATA[
+ei_reg_restore(fd, reg, "mtab"); ]]></code>
+ <p>This will read the entire contents of <c><![CDATA["mtab"]]></c> into the specified
+ registry. After the restore, all of the objects in the registry will
+ be marked as unmodified, so a subsequent backup will only affect
+ objects that you have modified since the restore.</p>
+ <p>Note that if you restore to a non-empty registry, objects in the
+ table will overwrite objects in the registry with the same keys. Also,
+ the <em>entire</em> contents of the registry is marked as unmodified
+ after the restore, including any modified objects that were not
+ overwritten by the restore operation. This may not be your intention.</p>
+ </section>
+
+ <section>
+ <title>Storing Strings and Binaries</title>
+ <p>When string or binary objects are stored in the registry it is
+ important that a number of simple guidelines are followed. </p>
+ <p>Most importantly, the object must have been created with a single call
+ to <c><![CDATA[malloc()]]></c> (or similar), so that it can later be removed by a
+ single call to <c><![CDATA[free()]]></c>. Objects will be freed by the registry
+ when it is closed, or when you assign a new value to an object that
+ previously contained a string or binary.</p>
+ <p>You should also be aware that if you store binary objects that are
+ context-dependent (e.g. containing pointers or open file descriptors),
+ they will lose their meaning if they are backed up to a Mnesia table
+ and subsequently restored in a different context.</p>
+ <p>When you retrieve a stored string or binary value from the registry,
+ the registry maintains a pointer to the object and you are passed a
+ copy of that pointer. You should never free an object retrieved in
+ this manner because when the registry later attempts to free it, a
+ runtime error will occur that will likely cause the C-node to crash.</p>
+ <p>You are free to modify the contents of an object retrieved this way.
+ However when you do so, the registry will not be aware of the changes
+ you make, possibly causing it to be missed the next time you make a
+ Mnesia backup of the registry contents. This can be avoided if you
+ mark the object as dirty after any such changes with
+ <c><![CDATA[ei_reg_markdirty()]]></c>, or pass appropriate flags to
+ <c><![CDATA[ei_reg_dump()]]></c>.</p>
+ </section>
+ </section>
+</chapter>
+
diff --git a/lib/erl_interface/doc/src/erl_call.xml b/lib/erl_interface/doc/src/erl_call.xml
new file mode 100644
index 0000000000..2d88e7616a
--- /dev/null
+++ b/lib/erl_interface/doc/src/erl_call.xml
@@ -0,0 +1,240 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE comref SYSTEM "comref.dtd">
+
+<comref>
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>erl_call</title>
+ <prepared>Torbj&ouml;rn T&ouml;rnkvist</prepared>
+ <responsible>Torbj&ouml;rn T&ouml;rnkvist</responsible>
+ <docno></docno>
+ <approved>Bjarne D&auml;cker</approved>
+ <checked>Torbj&ouml;rn T&ouml;rnkvist</checked>
+ <date>97-05-16</date>
+ <rev>B</rev>
+ <file>erl_call.sgml</file>
+ </header>
+ <com>erl_call</com>
+ <comsummary>Call/Start a Distributed Erlang Node</comsummary>
+ <description>
+ <p><c><![CDATA[erl_call]]></c> makes it possible to start and/or communicate with
+ a distributed Erlang node. It is built upon the <c><![CDATA[erl_interface]]></c>
+ library as an example application. Its purpose is to use an Unix shell script to interact with a distributed Erlang node. It performs all
+ communication with the Erlang <em>rex server</em>, using the standard Erlang RPC facility. It does not require any special
+ software to be run at the Erlang target node.</p>
+ <p>The main use is to either start a distributed Erlang node
+ or to make an ordinary function call. However, it is also
+ possible to pipe an Erlang module to <c><![CDATA[erl_call]]></c> and have it
+ compiled, or to pipe a sequence of Erlang expressions to be evaluated
+ (similar to the Erlang shell).</p>
+ <p>Options, which cause <c><![CDATA[stdin]]></c> to be read, can be used with
+ advantage
+ as scripts from within (Unix) shell scripts. Another
+ nice use of <c><![CDATA[erl_call]]></c> could be from (http) CGI-bin scripts.</p>
+ </description>
+ <funcs>
+ <func>
+ <name>erl_call &lt;options></name>
+ <fsummary>Start/Call Erlang</fsummary>
+ <desc>
+ <p>Each option flag is described below with its name, type and
+ meaning. </p>
+ <taglist>
+ <tag>-a [Mod [Fun [Args]]]]</tag>
+ <item>
+ <p>(<em>optional</em>): Applies the specified function
+ and returns the result. <c><![CDATA[Mod]]></c> must be specified, however
+ <em>[]</em> is assumed for unspecified <c><![CDATA[Fun]]></c> and <c><![CDATA[Args]]></c>. <c><![CDATA[Args]]></c> should
+ be in the same format as for <c><![CDATA[erlang:apply/3]]></c>. Note
+ that this flag takes exactly one argument, so quoting
+ may be necessary in order to group <c><![CDATA[Mod]]></c>, <c><![CDATA[Fun]]></c>
+ and <c><![CDATA[Args]]></c>, in a manner dependent on the behavior
+ of your command shell.</p>
+ <p></p>
+ </item>
+ <tag>-c Cookie</tag>
+ <item>
+ <p>(<em>optional</em>): Use this option to specify a certain cookie. If no cookie is specified, the <c><![CDATA[~/.erlang.cookie]]></c> file is read and its content are used as cookie. The Erlang node we want to communicate with must have the same cookie.</p>
+ </item>
+ <tag>-d</tag>
+ <item>
+ <p>(<em>optional</em>): Debug mode. This causes all IO to be output
+ to the file <c><![CDATA[~/.erl_call.out.Nodename]]></c>, where <c><![CDATA[Nodename]]></c>
+ is the node name of the Erlang node in question.</p>
+ <p></p>
+ </item>
+ <tag>-e</tag>
+ <item>
+ <p>(<em>optional</em>): Reads a sequence of Erlang expressions, separated
+ by '<em>,</em>' and ended with a '<em>.</em>', from <c><![CDATA[stdin]]></c> until
+ EOF (Control-D). Evaluates the expressions and returns the result from
+ the last expression. Returns <c><![CDATA[{ok,Result}]]></c> if successful.</p>
+ <p></p>
+ </item>
+ <tag>-h HiddenName</tag>
+ <item>
+ <p>(<em>optional</em>): Specifies the name of the hidden node
+ that <c><![CDATA[erl_call]]></c> represents.</p>
+ <p></p>
+ </item>
+ <tag>-m</tag>
+ <item>
+ <p>(<em>optional</em>): Reads an Erlang module from <c><![CDATA[stdin]]></c> and
+ compiles it.</p>
+ <p></p>
+ </item>
+ <tag>-n Node</tag>
+ <item>
+ <p>(one of <c><![CDATA[-n, -name, -sname]]></c> is required):
+ Has the same meaning as <c><![CDATA[-name]]></c> and can still be used for
+ backwards compatibility reasons.</p>
+ <p></p>
+ </item>
+ <tag>-name Node</tag>
+ <item>
+ <p>(one of <c><![CDATA[-n, -name, -sname]]></c> is required): <c><![CDATA[Node]]></c> is the name of the node to be
+ started or communicated with. It is assumed that
+ <c><![CDATA[Node]]></c> is started with <c><![CDATA[erl -name]]></c>, which means that fully
+ qualified long node names are used.
+ If the <c><![CDATA[-s]]></c> option is given, an Erlang node will (if necessary)
+ be started with <c><![CDATA[erl -name]]></c>.</p>
+ <p></p>
+ </item>
+ <tag>-q</tag>
+ <item>
+ <p>(<em>optional</em>): Halts the Erlang node specified
+ with the -n switch. This switch overrides the -s switch.</p>
+ <p></p>
+ </item>
+ <tag>-r</tag>
+ <item>
+ <p>(<em>optional</em>): Generates a random name of the hidden node
+ that <c><![CDATA[erl_call]]></c> represents.</p>
+ <p></p>
+ </item>
+ <tag>-s</tag>
+ <item>
+ <p>(<em>optional</em>): Starts a distributed Erlang node if necessary.
+ This means that in a sequence of calls, where the '<c><![CDATA[-s]]></c>'
+ and '<c><![CDATA[-n Node]]></c>' are constant, only the first call will start
+ the Erlang node. This makes the rest of the communication
+ very fast. This flag is currently only available on the Unix platform.</p>
+ <p></p>
+ </item>
+ <tag>-sname Node</tag>
+ <item>
+ <p>(one of <c><![CDATA[-n, -name, -sname]]></c> is required): <c><![CDATA[Node]]></c> is the name of the node to
+ be started or communicated with. It is assumed that <c><![CDATA[Node]]></c> is started with <c><![CDATA[erl -sname]]></c> which means that short node names are used.
+ If <c><![CDATA[-s]]></c> option is given, an Erlang node will be started (if necessary) with <c><![CDATA[erl -sname]]></c>.</p>
+ <p></p>
+ </item>
+ <tag>-v</tag>
+ <item>
+ <p>(<em>optional</em>): Prints a lot of <c><![CDATA[verbose]]></c> information.
+ This is only useful for the developer and maintainer of <c><![CDATA[erl_call]]></c>.</p>
+ <p></p>
+ </item>
+ <tag>-x ErlScript</tag>
+ <item>
+ <p>(<em>optional</em>): Specifies another name of the Erlang start-up script
+ to be used. If not specified, the standard <c><![CDATA[erl]]></c> start-up script
+ is used.</p>
+ </item>
+ </taglist>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>Examples</title>
+ <p>Starts an Erlang node and calls <c><![CDATA[erlang:time/0]]></c>.</p>
+ <code type="none"><![CDATA[
+erl_call -s -a 'erlang time' -n madonna
+{18,27,34}
+ ]]></code>
+ <p>Terminates an Erlang node by calling <c><![CDATA[erlang:halt/0]]></c>.</p>
+ <code type="none"><![CDATA[
+erl_call -s -a 'erlang halt' -n madonna
+ ]]></code>
+ <p>An apply with several arguments.</p>
+ <code type="none"><![CDATA[
+erl_call -s -a 'lists map [{math,sqrt},[1,4,9,16,25]]' -n madonna
+ ]]></code>
+ <p>Evaluates a couple of expressions. <b>The input ends with EOF (Control-D)</b>.</p>
+ <code type="none"><![CDATA[
+erl_call -s -e -n madonna
+statistics(runtime),
+X=1,
+Y=2,
+{_,T}=statistics(runtime),
+{X+Y,T}.
+^D
+{ok,{3,0}}
+ ]]></code>
+ <p>Compiles a module and runs it. <b>Again, the input ends with EOF (Control-D)</b>. (In the example shown, the output has been formatted afterwards).</p>
+ <code type="none"><![CDATA[
+erl_call -s -m -a lolita -n madonna
+-module(lolita).
+-compile(export_all).
+start() ->
+ P = processes(),
+ F = fun(X) -> {X,process_info(X,registered_name)} end,
+ lists:map(F,[],P).
+^D
+ {registered_name,init}},
+ {registered_name,erl_prim_loader}},
+ {registered_name,error_logger}},
+ {registered_name,application_controller}},
+ {registered_name,kernel}},
+ []},
+ {registered_name,kernel_sup}},
+ {registered_name,net_sup}},
+ {registered_name,net_kernel}},
+ []},
+ {registered_name,global_name_server}},
+ {registered_name,auth}},
+ {registered_name,rex}},
+ []},
+ {registered_name,file_server}},
+ {registered_name,code_server}},
+ {registered_name,user}},
+ []}]
+ ]]></code>
+ </section>
+</comref>
+
diff --git a/lib/erl_interface/doc/src/erl_connect.xml b/lib/erl_interface/doc/src/erl_connect.xml
new file mode 100644
index 0000000000..b2235925b2
--- /dev/null
+++ b/lib/erl_interface/doc/src/erl_connect.xml
@@ -0,0 +1,566 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE cref SYSTEM "cref.dtd">
+
+<cref>
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>erl_connect</title>
+ <prepared>Torbj&ouml;rn T&ouml;rnkvist</prepared>
+ <responsible>Torbj&ouml;rn T&ouml;rnkvist</responsible>
+ <docno></docno>
+ <approved>Bjarne D&auml;cker</approved>
+ <checked>Torbj&ouml;rn T&ouml;rnkvist</checked>
+ <date>980703</date>
+ <rev>A</rev>
+ <file>erl_connect.sgml</file>
+ </header>
+ <lib>erl_connect</lib>
+ <libsummary>Communicate with Distributed Erlang</libsummary>
+ <description>
+ <p>This module provides support for communication between distributed
+ Erlang nodes and C nodes, in a manner that is transparent to Erlang
+ processes.</p>
+ <p>A C node appears to Erlang as a
+ <em>hidden node</em>.
+ That is, Erlang processes that know the name of the
+ C node are able to communicate with it in a normal manner, but
+ the node name will not appear in the listing provided by the
+ Erlang function <c><![CDATA[nodes/0]]></c>.</p>
+ </description>
+ <funcs>
+ <func>
+ <name><ret>int</ret><nametext>erl_connect_init(number, cookie, creation)</nametext></name>
+ <name><ret>int</ret><nametext>erl_connect_xinit(host, alive, node, addr, cookie, creation)</nametext></name>
+ <fsummary>Initialize communication</fsummary>
+ <type>
+ <v>int number;</v>
+ <v>char *cookie;</v>
+ <v>short creation;</v>
+ <v>char *host,*alive,*node;</v>
+ <v>struct in_addr *addr;</v>
+ </type>
+ <desc>
+ <p>These functions initialize the <c><![CDATA[erl_connect]]></c>
+ module. In particular, they are used to identify the name of the
+ C-node from which they are called. One of these functions must
+ be called before any of the other functions in the erl_connect
+ module are used.</p>
+ <p><c><![CDATA[erl_connect_xinit()]]></c> stores for later use information about
+ the node's host name <c><![CDATA[host]]></c>, alive name <c><![CDATA[alive]]></c>, node
+ name <c><![CDATA[node]]></c>, IP address <c><![CDATA[addr]]></c>, cookie <c><![CDATA[cookie]]></c>,
+ and creation number <c><![CDATA[creation]]></c>. <c><![CDATA[erl_connect_init()]]></c>
+ provides an alternative interface which does not require as much
+ information from the caller. Instead, <c><![CDATA[erl_connect_init()]]></c>
+ uses <c><![CDATA[gethostbyname()]]></c> to obtain default values.
+ </p>
+ <p>If you use <c><![CDATA[erl_connect_init()]]></c> your node will have a
+ short name, i.e., it will not be fully qualified. If you need to
+ use fully qualified (a.k.a. long) names, use
+ <c><![CDATA[erl_connect_xinit()]]></c> instead.
+ </p>
+ <p><c><![CDATA[host]]></c> is the name of the host on which the node is running.</p>
+ <p><c><![CDATA[alive]]></c> is the alivename of the node.</p>
+ <p><c><![CDATA[node]]></c> is the name of the node. The nodename should
+ be of the form <em>alivename@hostname</em>.</p>
+ <p><c><![CDATA[addr]]></c> is the 32-bit IP address of <c><![CDATA[host]]></c>.</p>
+ <p><c><![CDATA[cookie]]></c> is the authorization string required for access
+ to the remote node. If NULL the user HOME directory is
+ searched for a cookie file <c><![CDATA[.erlang.cookie]]></c>. The path to
+ the home directory is retrieved from the environment variable
+ <c><![CDATA[HOME]]></c> on Unix and from the <c><![CDATA[HOMEDRIVE]]></c> and
+ <c><![CDATA[HOMEPATH]]></c> variables on Windows. Refer to the <c><![CDATA[auth]]></c>
+ module for more details.</p>
+ <p><c><![CDATA[creation]]></c> helps identify a particular instance of a C
+ node. In particular, it can help prevent us from receiving
+ messages sent to an earlier process with the same registered
+ name.</p>
+ <p>A C node acting as a server will be assigned a creation number
+ when it calls <c><![CDATA[erl_publish()]]></c>.</p>
+ <p><c><![CDATA[number]]></c> is used by <c><![CDATA[erl_connect_init()]]></c> to
+ construct the actual node name. In the second example shown
+ below, <em>"[email protected]"</em> will be the resulting node
+ name.</p>
+ <p>Example 1:</p>
+ <code type="none"><![CDATA[
+struct in_addr addr;
+addr = inet_addr("150.236.14.75");
+if (!erl_connect_xinit("chivas",
+ "madonna",
+ &addr;
+ "samplecookiestring..."),
+ 0)
+ erl_err_quit("<ERROR> when initializing !");
+ ]]></code>
+ <p>Example 2:</p>
+ <code type="none"><![CDATA[
+if (!erl_connect_init(17, "samplecookiestring...", 0))
+ erl_err_quit("<ERROR> when initializing !");
+ ]]></code>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_connect(node)</nametext></name>
+ <name><ret>int</ret><nametext>erl_xconnect(addr, alive)</nametext></name>
+ <fsummary>Establishe a connection to an Erlang node</fsummary>
+ <type>
+ <v>char *node, *alive;</v>
+ <v>struct in_addr *addr;</v>
+ </type>
+ <desc>
+ <p>These functions set up a connection to an Erlang node.</p>
+ <p><c><![CDATA[erl_xconnect()]]></c> requires the IP address of the remote
+ host and the alive name of the remote node
+ to be specified. <c><![CDATA[erl_connect()]]></c> provides an alternative
+ interface, and determines the information from the node name
+ provided.</p>
+ <p><c><![CDATA[addr]]></c> is the 32-bit IP address of the remote host.</p>
+ <p><c><![CDATA[alive]]></c> is the alivename of the remote node.</p>
+ <p><c><![CDATA[node]]></c> is the name of the remote node.</p>
+ <p>These functions return an open file descriptor on success, or
+ a negative value indicating that an error occurred --- in
+ which case they will set <c><![CDATA[erl_errno]]></c> to one of:</p>
+ <taglist>
+ <tag><c><![CDATA[EHOSTUNREACH]]></c></tag>
+ <item>The remote host <c><![CDATA[node]]></c> is unreachable</item>
+ <tag><c><![CDATA[ENOMEM]]></c></tag>
+ <item>No more memory available.</item>
+ <tag><c><![CDATA[EIO]]></c></tag>
+ <item>I/O error.</item>
+ </taglist>
+ <p>Additionally, <c><![CDATA[errno]]></c> values from
+ <c><![CDATA[socket]]></c><em>(2)</em> and <c><![CDATA[connect]]></c><em>(2)</em>
+ system calls may be propagated into <c><![CDATA[erl_errno]]></c>.</p>
+ <code type="none"><![CDATA[
+#define NODE "[email protected]"
+#define ALIVE "madonna"
+#define IP_ADDR "150.236.14.75"
+
+/*** Variant 1 ***/
+erl_connect( NODE );
+
+/*** Variant 2 ***/
+struct in_addr addr;
+addr = inet_addr(IP_ADDR);
+erl_xconnect( &addr , ALIVE );
+ ]]></code>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_close_connection(fd)</nametext></name>
+ <fsummary>Close a connection to an Erlang node</fsummary>
+ <type>
+ <v>int fd;</v>
+ </type>
+ <desc>
+ <p>This function closes an open connection to an Erlang node.</p>
+ <p><c><![CDATA[Fd]]></c> is a file descriptor obtained from
+ <c><![CDATA[erl_connect()]]></c> or <c><![CDATA[erl_xconnect()]]></c>.</p>
+ <p>On success, 0 is returned. If the call fails, a non-zero value
+ is returned, and the reason for
+ the error can be obtained with the appropriate platform-dependent
+ call.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_receive(fd, bufp, bufsize)</nametext></name>
+ <fsummary>Receive a message</fsummary>
+ <type>
+ <v>int fd;</v>
+ <v>char *bufp;</v>
+ <v>int bufsize;</v>
+ </type>
+ <desc>
+ <p>This function receives a message consisting of a sequence
+ of bytes in the Erlang external format.</p>
+ <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
+ <p><c><![CDATA[bufp]]></c> is a buffer large enough to hold the expected
+ message. </p>
+ <p><c><![CDATA[bufsize]]></c> indicates the size of <c><![CDATA[bufp]]></c>.</p>
+ <p>If a <em>tick</em> occurs, i.e., the Erlang node on the
+ other end of the connection has polled this node to see if it
+ is still alive, the function will return <c><![CDATA[ERL_TICK]]></c> and
+ no message will be placed in the buffer. Also,
+ <c><![CDATA[erl_errno]]></c> will be set to <c><![CDATA[EAGAIN]]></c>.</p>
+ <p>On success, the message is placed in the specified buffer
+ and the function returns the number of bytes actually read. On
+ failure, the function returns a negative value and will set
+ <c><![CDATA[erl_errno]]></c> to one of:</p>
+ <taglist>
+ <tag><c><![CDATA[EAGAIN]]></c></tag>
+ <item>Temporary error: Try again.</item>
+ <tag><c><![CDATA[EMSGSIZE]]></c></tag>
+ <item>Buffer too small.</item>
+ <tag><c><![CDATA[EIO]]></c></tag>
+ <item>I/O error.</item>
+ </taglist>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_receive_msg(fd, bufp, bufsize, emsg)</nametext></name>
+ <fsummary>Receive and decodes a message</fsummary>
+ <type>
+ <v>int fd;</v>
+ <v>unsigned char *bufp;</v>
+ <v>int bufsize;</v>
+ <v>ErlMessage *emsg;</v>
+ </type>
+ <desc>
+ <p>This function receives the message into the specified buffer,
+ and decodes into the <c><![CDATA[(ErlMessage *) emsg]]></c>.</p>
+ <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
+ <p><c><![CDATA[bufp]]></c> is a buffer large enough to hold the expected message.</p>
+ <p><c><![CDATA[bufsize]]></c> indicates the size of <c><![CDATA[bufp]]></c>.</p>
+ <p><c><![CDATA[emsg]]></c> is a pointer to an <c><![CDATA[ErlMessage]]></c> structure,
+ into which the message will be decoded. <c><![CDATA[ErlMessage]]></c> is
+ defined as follows:</p>
+ <code type="none"><![CDATA[
+typedef struct {
+ int type;
+ ETERM *msg;
+ ETERM *to;
+ ETERM *from;
+ char to_name[MAXREGLEN];
+} ErlMessage;
+ ]]></code>
+ <note>
+ <p>The definition of <c><![CDATA[ErlMessage]]></c> has changed since
+ earlier versions of Erl_Interface.</p>
+ </note>
+ <p><c><![CDATA[type]]></c> identifies the type of message, one of
+ <c><![CDATA[ERL_SEND]]></c>, <c><![CDATA[ERL_REG_SEND]]></c>, <c><![CDATA[ERL_LINK]]></c>,
+ <c><![CDATA[ERL_UNLINK]]></c> and <c><![CDATA[ERL_EXIT]]></c>.
+ </p>
+ <p>If <c><![CDATA[type]]></c> contains <c><![CDATA[ERL_SEND]]></c>
+ this indicates that an ordinary send operation has taken
+ place, and <c><![CDATA[emsg->to]]></c> contains the Pid of the
+ recipient. If <c><![CDATA[type]]></c> contains <c><![CDATA[ERL_REG_SEND]]></c> then a
+ registered send operation took place, and <c><![CDATA[emsg->from]]></c>
+ contains the Pid of the sender. In both cases, the actual
+ message will be in <c><![CDATA[emsg->msg]]></c>.
+ </p>
+ <p>If <c><![CDATA[type]]></c> contains one of <c><![CDATA[ERL_LINK]]></c> or
+ <c><![CDATA[ERL_UNLINK]]></c>, then <c><![CDATA[emsg->to]]></c> and <c><![CDATA[emsg->from]]></c>
+ contain the pids of the sender and recipient of the link or unlink.
+ <c><![CDATA[emsg->msg]]></c> is not used in these cases.
+ </p>
+ <p>If <c><![CDATA[type]]></c> contains <c><![CDATA[ERL_EXIT]]></c>, then this
+ indicates that a link has been broken. In this case,
+ <c><![CDATA[emsg->to]]></c> and <c><![CDATA[emsg->from]]></c> contain the pids of the
+ linked processes, and <c><![CDATA[emsg->msg]]></c> contains the reason for
+ the exit.
+ </p>
+ <note>
+ <p>It is the caller's responsibility to release the
+ memory pointed to by <c><![CDATA[emsg->msg]]></c>, <c><![CDATA[emsg->to]]></c> and
+ <c><![CDATA[emsg->from]]></c>.</p>
+ </note>
+ <p>If a <em>tick</em> occurs, i.e., the Erlang node on the
+ other end of the connection has polled this node to see if it
+ is still alive, the function will return <c><![CDATA[ERL_TICK]]></c>
+ indicating that the tick has been received and responded to,
+ but no message will be placed in the buffer. In this case you
+ should call <c><![CDATA[erl_receive_msg()]]></c> again.</p>
+ <p>On success, the function returns <c><![CDATA[ERL_MSG]]></c> and the
+ <c><![CDATA[Emsg]]></c> struct will be initialized as described above, or
+ <c><![CDATA[ERL_TICK]]></c>, in which case no message is returned. On
+ failure, the function returns <c><![CDATA[ERL_ERROR]]></c> and will set
+ <c><![CDATA[erl_errno]]></c> to one of:</p>
+ <taglist>
+ <tag><c><![CDATA[EMSGSIZE]]></c></tag>
+ <item>Buffer too small.</item>
+ <tag><c><![CDATA[ENOMEM]]></c></tag>
+ <item>No more memory available.</item>
+ <tag><c><![CDATA[EIO]]></c></tag>
+ <item>I/O error.</item>
+ </taglist>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_xreceive_msg(fd, bufpp, bufsizep, emsg)</nametext></name>
+ <fsummary>Receive and decodes a message</fsummary>
+ <type>
+ <v>int fd;</v>
+ <v>unsigned char **bufpp;</v>
+ <v>int *bufsizep;</v>
+ <v>ErlMessage *emsg;</v>
+ </type>
+ <desc>
+ <p>This function is similar to <c><![CDATA[erl_receive_msg]]></c>. The
+ difference is that <c><![CDATA[erl_xreceive_msg]]></c> expects the buffer to
+ have been allocated by <c><![CDATA[malloc]]></c>, and reallocates it if the received
+ message does not fit into the original buffer. For that reason,
+ both buffer and buffer length are given as pointers - their values
+ may change by the call.
+ </p>
+ <p>On success, the function returns <c><![CDATA[ERL_MSG]]></c> and the
+ <c><![CDATA[Emsg]]></c> struct will be initialized as described above, or
+ <c><![CDATA[ERL_TICK]]></c>, in which case no message is returned. On
+ failure, the function returns <c><![CDATA[ERL_ERROR]]></c> and will set
+ <c><![CDATA[erl_errno]]></c> to one of:</p>
+ <taglist>
+ <tag><c><![CDATA[EMSGSIZE]]></c></tag>
+ <item>Buffer too small.</item>
+ <tag><c><![CDATA[ENOMEM]]></c></tag>
+ <item>No more memory available.</item>
+ <tag><c><![CDATA[EIO]]></c></tag>
+ <item>I/O error.</item>
+ </taglist>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_send(fd, to, msg)</nametext></name>
+ <fsummary>Send a message</fsummary>
+ <type>
+ <v>int fd;</v>
+ <v>ETERM *to, *msg;</v>
+ </type>
+ <desc>
+ <p>This function sends an Erlang term to a process.</p>
+ <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
+ <p><c><![CDATA[to]]></c> is an Erlang term containing the Pid of the
+ intended recipient of the message.</p>
+ <p><c><![CDATA[msg]]></c> is the Erlang term to be sent.</p>
+ <p>The function returns 1 if successful, otherwise 0 --- in
+ which case it will set <c><![CDATA[erl_errno]]></c> to one of:</p>
+ <taglist>
+ <tag><c><![CDATA[EINVAL]]></c></tag>
+ <item>Invalid argument: <c><![CDATA[to]]></c> is not a valid Erlang pid.</item>
+ <tag><c><![CDATA[ENOMEM]]></c></tag>
+ <item>No more memory available.</item>
+ <tag><c><![CDATA[EIO]]></c></tag>
+ <item>I/O error.</item>
+ </taglist>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_reg_send(fd, to, msg)</nametext></name>
+ <fsummary>Send a message to a registered name</fsummary>
+ <type>
+ <v>int fd;</v>
+ <v>char *to;</v>
+ <v>ETERM *msg;</v>
+ </type>
+ <desc>
+ <p>This function sends an Erlang term to a registered process.</p>
+ <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
+ <p><c><![CDATA[to]]></c> is a string containing the registered name of
+ the intended recipient of the message.</p>
+ <p><c><![CDATA[msg]]></c> is the Erlang term to be sent.</p>
+ <p>The function returns 1 if successful, otherwise 0 --- in
+ which case it will set <c><![CDATA[erl_errno]]></c> to one of:</p>
+ <taglist>
+ <tag><c><![CDATA[ENOMEM]]></c></tag>
+ <item>No more memory available.</item>
+ <tag><c><![CDATA[EIO]]></c></tag>
+ <item>I/O error.</item>
+ </taglist>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_rpc(fd, mod, fun, args)</nametext></name>
+ <name><ret>int</ret><nametext>erl_rpc_to(fd, mod, fun, args)</nametext></name>
+ <name><ret>int</ret><nametext>erl_rpc_from(fd, timeout, emsg)</nametext></name>
+ <fsummary>Remote Procedure Call</fsummary>
+ <type>
+ <v>int fd, timeout;</v>
+ <v>char *mod, *fun;</v>
+ <v>ETERM *args;</v>
+ <v>ErlMessage *emsg;</v>
+ </type>
+ <desc>
+ <p>These functions support calling Erlang functions on remote nodes.
+ <c><![CDATA[erl_rpc_to()]]></c> sends an rpc request to a remote node and
+ <c><![CDATA[erl_rpc_from()]]></c> receives the results of such a call.
+ <c><![CDATA[erl_rpc()]]></c> combines the functionality of these two functions
+ by sending an rpc request and waiting for the results. See also
+ <c><![CDATA[rpc:call/4]]></c>. </p>
+ <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.</p>
+ <p><c><![CDATA[timeout]]></c> is the maximum time (in ms) to wait for
+ results. Specify <c><![CDATA[ERL_NO_TIMEOUT]]></c> to wait forever.
+ When erl_rpc() calls erl_rpc_from(), the call will never
+ timeout.</p>
+ <p><c><![CDATA[mod]]></c> is the name of the module containing the function
+ to be run on the remote node.</p>
+ <p><c><![CDATA[fun]]></c> is the name of the function to run.</p>
+ <p><c><![CDATA[args]]></c> is an Erlang list, containing the arguments to be
+ passed to the function. </p>
+ <p><c><![CDATA[emsg]]></c> is a message containing the result of the
+ function call.</p>
+ <p>The actual message returned by the rpc server
+ is a 2-tuple <c><![CDATA[{rex,Reply}]]></c>. If you are using
+ <c><![CDATA[erl_rpc_from()]]></c> in your code then this is the message you
+ will need to parse. If you are using <c><![CDATA[erl_rpc()]]></c> then the
+ tuple itself is parsed for you, and the message returned to your
+ program is the erlang term containing <c><![CDATA[Reply]]></c> only. Replies
+ to rpc requests are always ERL_SEND messages.
+ </p>
+ <note>
+ <p>It is the caller's responsibility to free the returned
+ <c><![CDATA[ETERM]]></c> structure as well as the memory pointed to by
+ <c><![CDATA[emsg->msg]]></c> and <c><![CDATA[emsg->to]]></c>. </p>
+ </note>
+ <p><c><![CDATA[erl_rpc()]]></c> returns the remote function's return value (or
+ <c><![CDATA[NULL]]></c> if it failed). <c><![CDATA[erl_rpc_to()]]></c> returns 0 on
+ success, and a negative number on failure. <c><![CDATA[erl_rcp_from()]]></c>
+ returns <c><![CDATA[ERL_MSG]]></c> when successful (with <c><![CDATA[Emsg]]></c> now
+ containing the reply tuple), and one of <c><![CDATA[ERL_TICK]]></c>,
+ <c><![CDATA[ERL_TIMEOUT]]></c> and <c><![CDATA[ERL_ERROR]]></c> otherwise. When failing,
+ all three functions set <c><![CDATA[erl_errno]]></c> to one of:</p>
+ <taglist>
+ <tag><c><![CDATA[ENOMEM]]></c></tag>
+ <item>No more memory available.</item>
+ <tag><c><![CDATA[EIO]]></c></tag>
+ <item>I/O error.</item>
+ <tag><c><![CDATA[ETIMEDOUT]]></c></tag>
+ <item>Timeout expired.</item>
+ <tag><c><![CDATA[EAGAIN]]></c></tag>
+ <item>Temporary error: Try again.</item>
+ </taglist>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_publish(port)</nametext></name>
+ <fsummary>Publish a node name</fsummary>
+ <type>
+ <v>int port;</v>
+ </type>
+ <desc>
+ <p>These functions are used by a server process to register
+ with the local name server <em>epmd</em>, thereby allowing
+ other processes to send messages by using the registered name.
+ Before calling either of these functions, the process should
+ have called <c><![CDATA[bind()]]></c> and <c><![CDATA[listen()]]></c> on an open socket.</p>
+ <p><c><![CDATA[port]]></c> is the local name to register, and should be the
+ same as the port number that was previously bound to the socket.</p>
+ <p>To unregister with epmd, simply close the returned
+ descriptor. See also <c><![CDATA[erl_unpublish()]]></c>.
+ </p>
+ <p>On success, the functions return a descriptor connecting the
+ calling process to epmd. On failure, they return -1 and set
+ <c><![CDATA[erl_errno]]></c> to:</p>
+ <taglist>
+ <tag><c><![CDATA[EIO]]></c></tag>
+ <item>I/O error</item>
+ </taglist>
+ <p>Additionally, <c><![CDATA[errno]]></c> values from <c><![CDATA[socket]]></c><em>(2)</em>
+ and <c><![CDATA[connect]]></c><em>(2)</em> system calls may be propagated
+ into <c><![CDATA[erl_errno]]></c>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_accept(listensock, conp)</nametext></name>
+ <fsummary>Accept a connection</fsummary>
+ <type>
+ <v>int listensock;</v>
+ <v>ErlConnect *conp;</v>
+ </type>
+ <desc>
+ <p>This function is used by a server process to accept a
+ connection from a client process.</p>
+ <p><c><![CDATA[listensock]]></c> is an open socket descriptor on which
+ <c><![CDATA[listen()]]></c> has previously been called.</p>
+ <p><c><![CDATA[conp]]></c> is a pointer to an <c><![CDATA[ErlConnect]]></c> struct,
+ described as follows:</p>
+ <code type="none"><![CDATA[
+typedef struct {
+ char ipadr[4];
+ char nodename[MAXNODELEN];
+} ErlConnect;
+ ]]></code>
+ <p>On success, <c><![CDATA[conp]]></c> is filled in with the address and
+ node name of the connecting client and a file descriptor is
+ returned. On failure, <c><![CDATA[ERL_ERROR]]></c> is returned and
+ <c><![CDATA[erl_errno]]></c> is set to <c><![CDATA[EIO]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>const char *</ret><nametext>erl_thiscookie()</nametext></name>
+ <name><ret>const char *</ret><nametext>erl_thisnodename()</nametext></name>
+ <name><ret>const char *</ret><nametext>erl_thishostname()</nametext></name>
+ <name><ret>const char *</ret><nametext>erl_thisalivename()</nametext></name>
+ <name><ret>short</ret><nametext>erl_thiscreation()</nametext></name>
+ <fsummary>Retrieve some values</fsummary>
+ <desc>
+ <p>These functions can be used to retrieve information about
+ the C Node. These values are initially set with
+ <c><![CDATA[erl_connect_init()]]></c> or <c><![CDATA[erl_connect_xinit()]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_unpublish(alive)</nametext></name>
+ <fsummary>Unpublish a node name</fsummary>
+ <type>
+ <v>char *alive;</v>
+ </type>
+ <desc>
+ <p>This function can be called by a process to unregister a
+ specified node name from epmd on the localhost. This may be
+ useful, for example, when epmd has not detected the failure of a
+ node, and will not allow the name to be reused. If you use this
+ function to unregister your own process, be sure to also close
+ the descriptor that was returned by <c><![CDATA[erl_publish()]]></c>.</p>
+ <note>
+ <p>Careless use of this function may have unpredictable
+ results, if the registered node is in fact still running.</p>
+ </note>
+ <p><c><![CDATA[alive]]></c> is the name of the node to unregister, i.e., the
+ first component of the nodename, without the <c><![CDATA[@hostname]]></c>.</p>
+ <p>If the node was successfully unregistered from epmd, the
+ function returns 0. Otherwise, it returns -1 and sets
+ <c><![CDATA[erl_errno]]></c> is to <c><![CDATA[EIO]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>struct hostent</ret><nametext>*erl_gethostbyname(name)</nametext></name>
+ <name><ret>struct hostent</ret><nametext>*erl_gethostbyaddr(addr, length, type)</nametext></name>
+ <name><ret>struct hostent</ret><nametext>*erl_gethostbyname_r(name, hostp, buffer, buflen, h_errnop)</nametext></name>
+ <name><ret>struct hostent</ret><nametext>*erl_gethostbyaddr_r(addr, length, type, hostp, buffer, buflen, h_errnop)</nametext></name>
+ <fsummary>Name lookup functions</fsummary>
+ <type>
+ <v>const char *name;</v>
+ <v>const char *addr;</v>
+ <v>int length;</v>
+ <v>int type;</v>
+ <v>struct hostent *hostp;</v>
+ <v>char *buffer;</v>
+ <v>int buflen;</v>
+ <v>int *h_errnop;</v>
+ </type>
+ <desc>
+ <p>These are convenience functions for some common name lookup functions.</p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>Debug Information</title>
+ <p>If a connection attempt fails, the following can be checked:</p>
+ <list type="bulleted">
+ <item><c><![CDATA[erl_errno]]></c></item>
+ <item>that the right cookie was used</item>
+ <item>that <em>epmd</em> is running</item>
+ <item>the remote Erlang node on the other side is running the same
+ version of Erlang as the <c><![CDATA[erl_interface]]></c> library.</item>
+ </list>
+ </section>
+</cref>
+
diff --git a/lib/erl_interface/doc/src/erl_error.xml b/lib/erl_interface/doc/src/erl_error.xml
new file mode 100644
index 0000000000..4a3f34fac7
--- /dev/null
+++ b/lib/erl_interface/doc/src/erl_error.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE cref SYSTEM "cref.dtd">
+
+<cref>
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>erl_error</title>
+ <prepared>Torbj&ouml;rn T&ouml;rnkvist</prepared>
+ <responsible>Torbj&ouml;rn T&ouml;rnkvist</responsible>
+ <docno></docno>
+ <approved>Bjarne D&auml;cker</approved>
+ <checked>Torbj&ouml;rn T&ouml;rnkvist</checked>
+ <date>961014</date>
+ <rev>A</rev>
+ <file>erl_error.sgml</file>
+ </header>
+ <lib>erl_error</lib>
+ <libsummary>Error Print Routines</libsummary>
+ <description>
+ <p>This module contains some error printing routines taken
+ from <em>Advanced Programming in the UNIX Environment</em>
+ by W. Richard Stevens. </p>
+ <p>These functions are all called in the same manner as
+ <c><![CDATA[printf()]]></c>, i.e. with a string containing format specifiers
+ followed by a list of corresponding arguments. All output from
+ these functions is to <c><![CDATA[stderr]]></c>.</p>
+ </description>
+ <funcs>
+ <func>
+ <name><ret>void</ret><nametext>erl_err_msg(FormatStr, ... )</nametext></name>
+ <fsummary>Non-fatal error, and not system call error</fsummary>
+ <type>
+ <v>const char *FormatStr;</v>
+ </type>
+ <desc>
+ <p>The message provided by the caller is printed. This
+ function is simply a wrapper for <c><![CDATA[fprintf()]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>void</ret><nametext>erl_err_quit(FormatStr, ... )</nametext></name>
+ <fsummary>Fatal error, but not system call error</fsummary>
+ <type>
+ <v>const char *FormatStr;</v>
+ </type>
+ <desc>
+ <p>Use this function when a fatal error has occurred that
+ is not due to a system call. The message provided by the
+ caller is printed and the process terminates with an exit
+ value of 1. The function does not return.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>void</ret><nametext>erl_err_ret(FormatStr, ... )</nametext></name>
+ <fsummary>Non-fatal system call error</fsummary>
+ <type>
+ <v>const char *FormatStr;</v>
+ </type>
+ <desc>
+ <p>Use this function after a failed system call. The message
+ provided by the caller is printed followed by a string
+ describing the reason for failure. </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>void</ret><nametext>erl_err_sys(FormatStr, ... )</nametext></name>
+ <fsummary>Fatal system call error</fsummary>
+ <type>
+ <v>const char *FormatStr;</v>
+ </type>
+ <desc>
+ <p>Use this function after a failed system call. The message
+ provided by the caller is printed followed by a string
+ describing the reason for failure, and the process
+ terminates with an exit value of 1. The function does not
+ return.</p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>Error Reporting</title>
+ <p>Most functions in erl_interface report failures to the caller by
+ returning some otherwise meaningless value (typically <c><![CDATA[NULL]]></c>
+ or a negative number). As this only tells you that things did not
+ go well, you will have to examine the error code in
+ <c><![CDATA[erl_errno]]></c> if you want to find out more about the failure.</p>
+ </section>
+ <funcs>
+ <func>
+ <name><ret>volatile int</ret><nametext>erl_errno</nametext></name>
+ <fsummary>The variable <c><![CDATA[erl_errno]]></c>contains the erl_interface error number. You can change the value if you wish. </fsummary>
+ <desc>
+ <p><c><![CDATA[erl_errno]]></c> is initially (at program startup) zero and
+ is then set by many erl_interface functions on failure to a
+ non-zero error code to indicate what kind of error it
+ encountered. A successful function call might change
+ <c><![CDATA[erl_errno]]></c> (by calling some other function that
+ fails), but no function will ever set it to zero. This means
+ that you cannot use <c><![CDATA[erl_errno]]></c> to see <em>if</em> a
+ function call failed. Instead, each function reports failure
+ in its own way (usually by returning a negative number or
+ <c><![CDATA[NULL]]></c>), in which case you can examine <c><![CDATA[erl_errno]]></c>
+ for details.</p>
+ <p><c><![CDATA[erl_errno]]></c> uses the error codes defined in your
+ system's <c><![CDATA[<errno.h>]]></c>.</p>
+ <note>
+ <p>Actually, <c><![CDATA[erl_errno]]></c> is a "modifiable lvalue" (just
+ like ISO C defines <c><![CDATA[errno]]></c> to be) rather than a
+ variable. This means it might be implemented as a macro
+ (expanding to, e.g., <c><![CDATA[*_erl_errno()]]></c>). For reasons of
+ thread- (or task-)safety, this is exactly what we do on most
+ platforms.</p>
+ </note>
+ </desc>
+ </func>
+ </funcs>
+</cref>
+
diff --git a/lib/erl_interface/doc/src/erl_eterm.xml b/lib/erl_interface/doc/src/erl_eterm.xml
new file mode 100644
index 0000000000..ce14549672
--- /dev/null
+++ b/lib/erl_interface/doc/src/erl_eterm.xml
@@ -0,0 +1,675 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE cref SYSTEM "cref.dtd">
+
+<cref>
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>erl_eterm</title>
+ <prepared>Torbj&ouml;rn T&ouml;rnkvist</prepared>
+ <responsible>Torbj&ouml;rn T&ouml;rnkvist</responsible>
+ <docno></docno>
+ <approved>Bjarne D&auml;cker</approved>
+ <checked>Torbj&ouml;rn T&ouml;rnkvist</checked>
+ <date>980703</date>
+ <rev>A</rev>
+ <file>erl_eterm.sgml</file>
+ </header>
+ <lib>erl_eterm</lib>
+ <libsummary>Functions for Erlang Term Construction</libsummary>
+ <description>
+ <p>This module contains functions for creating and manipulating
+ Erlang terms. </p>
+ <p>An Erlang term is represented by a C structure of type
+ <c><![CDATA[ETERM]]></c>. Applications should not reference any fields in this
+ structure directly, because it may be changed in future releases
+ to provide faster and more compact term storage. Instead,
+ applications should us the macros and functions provided. </p>
+ <p>The following macros each take a single ETERM pointer as an
+ argument. They return a non-zero value if the test is true, and 0
+ otherwise:</p>
+ <taglist>
+ <tag><c><![CDATA[ERL_IS_INTEGER(t)]]></c></tag>
+ <item>True if <c><![CDATA[t]]></c> is an integer.</item>
+ <tag><c><![CDATA[ERL_IS_UNSIGNED_INTEGER(t)]]></c></tag>
+ <item>True if <c><![CDATA[t]]></c> is an integer.</item>
+ <tag><c><![CDATA[ERL_IS_FLOAT(t)]]></c></tag>
+ <item>True if <c><![CDATA[t]]></c> is a floating point number.</item>
+ <tag><c><![CDATA[ERL_IS_ATOM(t)]]></c></tag>
+ <item>True if <c><![CDATA[t]]></c> is an atom.</item>
+ <tag><c><![CDATA[ERL_IS_PID(t)]]></c></tag>
+ <item>True if <c><![CDATA[t]]></c> is a Pid (process identifier).</item>
+ <tag><c><![CDATA[ERL_IS_PORT(t)]]></c></tag>
+ <item>True if <c><![CDATA[t]]></c> is a port.</item>
+ <tag><c><![CDATA[ERL_IS_REF(t)]]></c></tag>
+ <item>True if <c><![CDATA[t]]></c> is a reference.</item>
+ <tag><c><![CDATA[ERL_IS_TUPLE(t)]]></c></tag>
+ <item>True if <c><![CDATA[t]]></c> is a tuple.</item>
+ <tag><c><![CDATA[ERL_IS_BINARY(t)]]></c></tag>
+ <item>True if <c><![CDATA[t]]></c> is a binary.</item>
+ <tag><c><![CDATA[ERL_IS_LIST(t)]]></c></tag>
+ <item>True if <c><![CDATA[t]]></c> is a list with zero or more elements.</item>
+ <tag><c><![CDATA[ERL_IS_EMPTY_LIST(t)]]></c></tag>
+ <item>True if <c><![CDATA[t]]></c> is an empty list.</item>
+ <tag><c><![CDATA[ERL_IS_CONS(t)]]></c></tag>
+ <item>True if <c><![CDATA[t]]></c> is a list with at least one element.</item>
+ </taglist>
+ <p>The following macros can be used for retrieving parts of Erlang
+ terms. None of these do any type checking; results are undefined
+ if you pass an ETERM* containing the wrong type. For example,
+ passing a tuple to ERL_ATOM_PTR() will likely result in garbage.
+ </p>
+ <taglist>
+ <tag><c><![CDATA[char *ERL_ATOM_PTR(t)]]></c></tag>
+ <item>A string representing atom <c><![CDATA[t]]></c>.
+ </item>
+ <tag><c><![CDATA[int ERL_ATOM_SIZE(t)]]></c></tag>
+ <item>The length (in characters) of atom t.</item>
+ <tag><c><![CDATA[void *ERL_BIN_PTR(t)]]></c></tag>
+ <item>A pointer to the contents of <c><![CDATA[t]]></c></item>
+ <tag><c><![CDATA[int ERL_BIN_SIZE(t)]]></c></tag>
+ <item>The length (in bytes) of binary object <c><![CDATA[t]]></c>.</item>
+ <tag><c><![CDATA[int ERL_INT_VALUE(t)]]></c></tag>
+ <item>The integer of <c><![CDATA[t]]></c>.</item>
+ <tag><c><![CDATA[unsigned int ERL_INT_UVALUE(t)]]></c></tag>
+ <item>The unsigned integer value of <c><![CDATA[t]]></c>.</item>
+ <tag><c><![CDATA[double ERL_FLOAT_VALUE(t)]]></c></tag>
+ <item>The floating point value of <c><![CDATA[t]]></c>.</item>
+ <tag><c><![CDATA[ETERM *ERL_PID_NODE(t)]]></c></tag>
+ <item>The Node in pid <c><![CDATA[t]]></c>.</item>
+ <tag><c><![CDATA[int ERL_PID_NUMBER(t)]]></c></tag>
+ <item>The sequence number in pid <c><![CDATA[t]]></c>.</item>
+ <tag><c><![CDATA[int ERL_PID_SERIAL(t)]]></c></tag>
+ <item>The serial number in pid <c><![CDATA[t]]></c>.</item>
+ <tag><c><![CDATA[int ERL_PID_CREATION(t)]]></c></tag>
+ <item>The creation number in pid <c><![CDATA[t]]></c>.</item>
+ <tag><c><![CDATA[int ERL_PORT_NUMBER(t)]]></c></tag>
+ <item>The sequence number in port <c><![CDATA[t]]></c>.</item>
+ <tag><c><![CDATA[int ERL_PORT_CREATION(t)]]></c></tag>
+ <item>The creation number in port <c><![CDATA[t]]></c>.</item>
+ <tag><c><![CDATA[ETERM *ERL_PORT_NODE(t)]]></c></tag>
+ <item>The node in port <c><![CDATA[t]]></c>.</item>
+ <tag><c><![CDATA[int ERL_REF_NUMBER(t)]]></c></tag>
+ <item>The first part of the reference number in ref <c><![CDATA[t]]></c>. Use
+ only for compatibility.</item>
+ <tag><c><![CDATA[int ERL_REF_NUMBERS(t)]]></c></tag>
+ <item>Pointer to the array of reference numbers in ref <c><![CDATA[t]]></c>.</item>
+ <tag><c><![CDATA[int ERL_REF_LEN(t)]]></c></tag>
+ <item>The number of used reference numbers in ref <c><![CDATA[t]]></c>.</item>
+ <tag><c><![CDATA[int ERL_REF_CREATION(t)]]></c></tag>
+ <item>The creation number in ref <c><![CDATA[t]]></c>.</item>
+ <tag><c><![CDATA[int ERL_TUPLE_SIZE(t)]]></c></tag>
+ <item>The number of elements in tuple <c><![CDATA[t]]></c>.</item>
+ <tag><c><![CDATA[ETERM *ERL_CONS_HEAD(t)]]></c></tag>
+ <item>The head element of list <c><![CDATA[t]]></c>.</item>
+ <tag><c><![CDATA[ETERM *ERL_CONS_TAIL(t)]]></c></tag>
+ <item>A List representing the tail elements of list <c><![CDATA[t]]></c>.</item>
+ </taglist>
+ </description>
+ <funcs>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_cons(head, tail)</nametext></name>
+ <fsummary>Prepends a term to the head of a list.</fsummary>
+ <type>
+ <v>ETERM *head;</v>
+ <v>ETERM *tail;</v>
+ </type>
+ <desc>
+ <p>This function concatenates two Erlang terms, prepending
+ <c><![CDATA[head]]></c> onto <c><![CDATA[tail]]></c> and thereby creating a <c><![CDATA[cons]]></c> cell.
+ To make a proper list, <c><![CDATA[tail]]></c> should always be a
+ list or an empty list. Note that NULL is not a valid list.</p>
+ <p><c><![CDATA[head]]></c> is the new term to be added.</p>
+ <p><c><![CDATA[tail]]></c> is the existing list to which <c><![CDATA[head]]></c> will
+ be concatenated.</p>
+ <p>The function returns a new list.</p>
+ <p><c><![CDATA[ERL_CONS_HEAD(list)]]></c> and <c><![CDATA[ERL_CONS_TAIL(list)]]></c>
+ can be used to retrieve the head and tail components
+ from the list. <c><![CDATA[erl_hd(list)]]></c> and <c><![CDATA[erl_tl(list)]]></c> will do
+ the same thing, but check that the argument really is a list.</p>
+ <p>For example:</p>
+ <code type="none"><![CDATA[
+ETERM *list,*anAtom,*anInt;
+anAtom = erl_mk_atom("madonna");
+anInt = erl_mk_int(21);
+list = erl_mk_empty_list();
+list = erl_cons(anAtom, list);
+list = erl_cons(anInt, list);
+ ... /* do some work */
+erl_free_compound(list);
+ ]]></code>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_copy_term(term)</nametext></name>
+ <fsummary>Creates a copy of an Erlang term</fsummary>
+ <type>
+ <v>ETERM *term;</v>
+ </type>
+ <desc>
+ <p>This function creates and returns a copy of the Erlang term
+ <c><![CDATA[term]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_element(position, tuple)</nametext></name>
+ <fsummary>Extracts an element from an Erlang tuple</fsummary>
+ <type>
+ <v>int position;</v>
+ <v>ETERM *tuple;</v>
+ </type>
+ <desc>
+ <p>This function extracts a specified element from an Erlang
+ tuple. </p>
+ <p><c><![CDATA[position]]></c> specifies which element to retrieve from
+ <c><![CDATA[tuple]]></c>. The elements are numbered starting from 1.</p>
+ <p><c><![CDATA[tuple]]></c> is an Erlang term containing at least
+ <c><![CDATA[position]]></c> elements.</p>
+ <p>The function returns a new Erlang term corresponding to the
+ requested element, or NULL if <c><![CDATA[position]]></c> was greater than
+ the arity of <c><![CDATA[tuple]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>void</ret><nametext>erl_init(NULL, 0)</nametext></name>
+ <fsummary>Initialization routine</fsummary>
+ <type>
+ <v>void *NULL;</v>
+ <v>int 0;</v>
+ </type>
+ <desc>
+ <marker id="erl_init"></marker>
+ <p>This function must be called before any of the others in
+ the <c><![CDATA[erl_interface]]></c> library in order to initialize the
+ library functions. The arguments must be specified as
+ <c><![CDATA[erl_init(NULL,0)]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_hd(list)</nametext></name>
+ <fsummary>Extracts the first element from a list</fsummary>
+ <type>
+ <v>ETERM *list;</v>
+ </type>
+ <desc>
+ <p>Extracts the first element from a list.</p>
+ <p><c><![CDATA[list]]></c> is an Erlang term containing a list.</p>
+ <p>The function returns an Erlang term corresponding to the
+ head element in the list, or a NULL pointer if <c><![CDATA[list]]></c> was
+ not a list.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_iolist_to_binary(term)</nametext></name>
+ <fsummary>Converts an IO list to a binary</fsummary>
+ <type>
+ <v>ETERM *list;</v>
+ </type>
+ <desc>
+ <p>This function converts an IO list to a binary term.</p>
+ <p><c><![CDATA[list]]></c> is an Erlang term containing a list.</p>
+ <p>This function an Erlang binary term, or NULL if <c><![CDATA[list]]></c>
+ was not an IO list. </p>
+ <p>Informally, an IO list is a deep list of characters and
+ binaries which can be sent to an Erlang port. In BNF, an IO
+ list is formally defined as follows: </p>
+ <code type="none"><![CDATA[
+iolist ::= []
+ | Binary
+ | [iohead | iolist]
+ ;
+iohead ::= Binary
+ | Byte (integer in the range [0..255])
+ | iolist
+ ;
+ ]]></code>
+ </desc>
+ </func>
+ <func>
+ <name><ret>char *</ret><nametext>erl_iolist_to_string(list)</nametext></name>
+ <fsummary>Converts an IO list to a zero terminated string</fsummary>
+ <type>
+ <v>ETERM *list;</v>
+ </type>
+ <desc>
+ <p>This function converts an IO list to a '\\0' terminated C
+ string. </p>
+ <p><c><![CDATA[list]]></c> is an Erlang term containing an IO list. The IO
+ list must not contain the integer 0, since C strings may not
+ contain this value except as a terminating marker.</p>
+ <p>This function returns a pointer to a dynamically allocated
+ buffer containing a string. If <c><![CDATA[list]]></c> is not an IO list,
+ or if <c><![CDATA[list]]></c> contains the integer 0, NULL is returned. It
+ is the caller's responsibility free the allocated buffer
+ with <c><![CDATA[erl_free()]]></c>. </p>
+ <p>Refer to <c><![CDATA[erl_iolist_to_binary()]]></c> for the definition of an
+ IO list. </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_iolist_length(list)</nametext></name>
+ <fsummary>Return the length of an IO list</fsummary>
+ <type>
+ <v>ETERM *list;</v>
+ </type>
+ <desc>
+ <p>Returns the length of an IO list.
+ </p>
+ <p><c><![CDATA[list]]></c> is an Erlang term containing an IO list. </p>
+ <p>The function returns the length of <c><![CDATA[list]]></c>, or -1 if
+ <c><![CDATA[list]]></c> is not an IO list.</p>
+ <p>Refer to <c><![CDATA[erl_iolist_to_binary()]]></c> for the definition of
+ an IO list. </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_length(list)</nametext></name>
+ <fsummary>Determines the length of a list</fsummary>
+ <type>
+ <v>ETERM *list;</v>
+ </type>
+ <desc>
+ <p>Determines the length of a proper list.</p>
+ <p><c><![CDATA[list]]></c> is an Erlang term containing proper list. In a
+ proper list, all tails except the last point to another list
+ cell, and the last tail points to an empty list.</p>
+ <p>Returns -1 if <c><![CDATA[list]]></c> is not a proper list.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_mk_atom(string)</nametext></name>
+ <fsummary>Creates an atom</fsummary>
+ <type>
+ <v>char *string;</v>
+ </type>
+ <desc>
+ <p>Creates an atom.</p>
+ <p><c><![CDATA[string]]></c> is the sequence of characters that will be
+ used to create the atom.</p>
+ <p>Returns an Erlang term containing an atom. Note that it is
+ the callers responsibility to make sure that <c><![CDATA[string]]></c>
+ contains a valid name for an atom.</p>
+ <p><c><![CDATA[ERL_ATOM_PTR(atom)]]></c> can be used to retrieve the
+ atom name (as a string). Note that the string is not
+ 0-terminated in the atom. <c><![CDATA[ERL_ATOM_SIZE(atom)]]></c>returns
+ the length of the atom name.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_mk_binary(bptr, size)</nametext></name>
+ <fsummary>Creates a binary object</fsummary>
+ <type>
+ <v>char *bptr;</v>
+ <v>int size;</v>
+ </type>
+ <desc>
+ <p>This function produces an Erlang binary object from a
+ buffer containing a sequence of bytes.</p>
+ <p><c><![CDATA[bptr]]></c> is a pointer to a buffer containing data to be converted.</p>
+ <p><c><![CDATA[size]]></c> indicates the length of <c><![CDATA[bptr]]></c>.</p>
+ <p>The function returns an Erlang binary object.</p>
+ <p><c><![CDATA[ERL_BIN_PTR(bin)]]></c> retrieves a pointer to
+ the binary data. <c><![CDATA[ERL_BIN_SIZE(bin)]]></c> retrieves the
+ size. </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_mk_empty_list()</nametext></name>
+ <fsummary>Creates an empty Erlang list</fsummary>
+ <desc>
+ <p>This function creates and returns an empty Erlang list.
+ Note that NULL is not used to represent an empty list;
+ Use this function instead.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_mk_estring(string, len)</nametext></name>
+ <fsummary>Creates an Erlang string</fsummary>
+ <type>
+ <v>char *string;</v>
+ <v>int len;</v>
+ </type>
+ <desc>
+ <p>This function creates a list from a sequence of bytes.</p>
+ <p><c><![CDATA[string]]></c> is a buffer containing a sequence of
+ bytes. The buffer does not need to be zero-terminated.</p>
+ <p><c><![CDATA[len]]></c> is the length of <c><![CDATA[string]]></c>.</p>
+ <p>The function returns an Erlang list object corresponding to
+ the character sequence in <c><![CDATA[string]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_mk_float(f)</nametext></name>
+ <fsummary>Creates an Erlang float</fsummary>
+ <type>
+ <v>double f;</v>
+ </type>
+ <desc>
+ <p>Creates an Erlang float.</p>
+ <p><c><![CDATA[f]]></c> is a value to be converted to an Erlang float.</p>
+ <p></p>
+ <p>The function returns an Erlang float object with the value
+ specified in <c><![CDATA[f]]></c>.</p>
+ <p><c><![CDATA[ERL_FLOAT_VALUE(t)]]></c> can be used to retrieve the
+ value from an Erlang float.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_mk_int(n)</nametext></name>
+ <fsummary>Creates an Erlang integer</fsummary>
+ <type>
+ <v>int n;</v>
+ </type>
+ <desc>
+ <p>Creates an Erlang integer.</p>
+ <p><c><![CDATA[n]]></c> is a value to be converted to an Erlang integer.</p>
+ <p></p>
+ <p>The function returns an Erlang integer object with the
+ value specified in <c><![CDATA[n]]></c>.</p>
+ <p><c><![CDATA[ERL_INT_VALUE(t)]]></c> can be used to retrieve the value
+ value from an Erlang integer.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_mk_list(array, arrsize)</nametext></name>
+ <fsummary>Creates a list from an array</fsummary>
+ <type>
+ <v>ETERM **array;</v>
+ <v>int arrsize;</v>
+ </type>
+ <desc>
+ <p>Creates an Erlang list from an array of Erlang terms, such
+ that each element in the list corresponds to one element in
+ the array. </p>
+ <p><c><![CDATA[array]]></c> is an array of Erlang terms.</p>
+ <p><c><![CDATA[arrsize]]></c> is the number of elements in <c><![CDATA[array]]></c>.</p>
+ <p>The function creates an Erlang list object, whose length
+ <c><![CDATA[arrsize]]></c> and whose elements are taken from the terms in
+ <c><![CDATA[array]]></c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_mk_pid(node, number, serial, creation)</nametext></name>
+ <fsummary>Creates a process identifier</fsummary>
+ <type>
+ <v>const char *node;</v>
+ <v>unsigned int number;</v>
+ <v>unsigned int serial;</v>
+ <v>unsigned int creation;</v>
+ </type>
+ <desc>
+ <p>This function creates an Erlang process identifier. The
+ resulting pid can be used by Erlang processes wishing to
+ communicate with the C node.</p>
+ <p><c><![CDATA[node]]></c> is the name of the C node.</p>
+ <p><c><![CDATA[number]]></c>, <c><![CDATA[serial]]></c> and <c><![CDATA[creation]]></c> are
+ arbitrary numbers. Note though, that these are limited in
+ precision, so only the low 15, 3 and 2 bits of these numbers
+ are actually used.</p>
+ <p>The function returns an Erlang pid object.</p>
+ <p><c><![CDATA[ERL_PID_NODE(pid)]]></c>, <c><![CDATA[ERL_PID_NUMBER(pid)]]></c>,
+ <c><![CDATA[ERL_PID_SERIAL(pid)]]></c> and <c><![CDATA[ERL_PID_CREATION(pid)]]></c>
+ can be used to retrieve the four values used to create the pid.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_mk_port(node, number, creation)</nametext></name>
+ <fsummary>Creates a port identifier</fsummary>
+ <type>
+ <v>const char *node;</v>
+ <v>unsigned int number;</v>
+ <v>unsigned int creation;</v>
+ </type>
+ <desc>
+ <p>This function creates an Erlang port identifier. </p>
+ <p><c><![CDATA[node]]></c> is the name of the C node.</p>
+ <p><c><![CDATA[number]]></c> and <c><![CDATA[creation]]></c> are arbitrary numbers.
+ Note though, that these are limited in
+ precision, so only the low 18 and 2 bits of these numbers
+ are actually used.</p>
+ <p>The function returns an Erlang port object.</p>
+ <p><c><![CDATA[ERL_PORT_NODE(port)]]></c>, <c><![CDATA[ERL_PORT_NUMBER(port)]]></c>
+ and <c><![CDATA[ERL_PORT_CREATION]]></c> can be used to retrieve the three
+ values used to create the port. </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_mk_ref(node, number, creation)</nametext></name>
+ <fsummary>Creates an old Erlang reference</fsummary>
+ <type>
+ <v>const char *node;</v>
+ <v>unsigned int number;</v>
+ <v>unsigned int creation;</v>
+ </type>
+ <desc>
+ <p>This function creates an old Erlang reference, with
+ only 18 bits - use <c><![CDATA[erl_mk_long_ref]]></c> instead.</p>
+ <p><c><![CDATA[node]]></c> is the name of the C node.</p>
+ <p><c><![CDATA[number]]></c> should be chosen uniquely for each reference
+ created for a given C node.</p>
+ <p><c><![CDATA[creation]]></c> is an arbitrary number.</p>
+ <p>Note that <c><![CDATA[number]]></c> and <c><![CDATA[creation]]></c> are limited in
+ precision, so only the low 18 and 2 bits of these numbers
+ are actually used.
+ </p>
+ <p>The function returns an Erlang reference object.</p>
+ <p><c><![CDATA[ERL_REF_NODE(ref)]]></c>, <c><![CDATA[ERL_REF_NUMBER(ref)]]></c>, and
+ <c><![CDATA[ERL_REF_CREATION(ref)]]></c> to retrieve the three values used
+ to create the reference. </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_mk_long_ref(node, n1, n2, n3, creation)</nametext></name>
+ <fsummary>Creates an Erlang reference</fsummary>
+ <type>
+ <v>const char *node;</v>
+ <v>unsigned int n1, n2, n3;</v>
+ <v>unsigned int creation;</v>
+ </type>
+ <desc>
+ <p>This function creates an Erlang reference, with 82 bits.</p>
+ <p><c><![CDATA[node]]></c> is the name of the C node.</p>
+ <p><c><![CDATA[n1]]></c>, <c><![CDATA[n2]]></c> and <c><![CDATA[n3]]></c> can be seen as one big number
+ <c><![CDATA[n1*2^64+n2*2^32+n3]]></c> which should be chosen uniquely for
+ each reference
+ created for a given C node.</p>
+ <p><c><![CDATA[creation]]></c> is an arbitrary number.</p>
+ <p>Note that <c><![CDATA[n3]]></c> and <c><![CDATA[creation]]></c> are limited in
+ precision, so only the low 18 and 2 bits of these numbers
+ are actually used.
+ </p>
+ <p>The function returns an Erlang reference object.</p>
+ <p><c><![CDATA[ERL_REF_NODE(ref)]]></c>, <c><![CDATA[ERL_REF_NUMBERS(ref)]]></c>,
+ <c><![CDATA[ERL_REF_LEN(ref)]]></c> and
+ <c><![CDATA[ERL_REF_CREATION(ref)]]></c> to retrieve the values used
+ to create the reference. </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_mk_string(string)</nametext></name>
+ <fsummary>Creates a string</fsummary>
+ <type>
+ <v>char *string;</v>
+ </type>
+ <desc>
+ <p>This function creates a list from a zero terminated string.</p>
+ <p><c><![CDATA[string]]></c> is the zero-terminated sequence of characters
+ (i.e. a C string) from which the list will be created.</p>
+ <p>The function returns an Erlang list.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_mk_tuple(array, arrsize)</nametext></name>
+ <fsummary>Creates an Erlang tuple from an array</fsummary>
+ <type>
+ <v>ETERM **array;</v>
+ <v>int arrsize;</v>
+ </type>
+ <desc>
+ <p>Creates an Erlang tuple from an array of Erlang terms.</p>
+ <p><c><![CDATA[array]]></c> is an array of Erlang terms.</p>
+ <p><c><![CDATA[arrsize]]></c> is the number of elements in <c><![CDATA[array]]></c>.</p>
+ <p>The function creates an Erlang tuple, whose arity is
+ <c><![CDATA[size]]></c> and whose elements are taken from the terms in
+ <c><![CDATA[array]]></c>.</p>
+ <p>To retrieve the size of a tuple, either use the
+ <c><![CDATA[erl_size]]></c> function (which checks the type of the checked
+ term and works for a binary as well as for a tuple), or the
+ <c><![CDATA[ERL_TUPLE_SIZE(tuple)]]></c> returns the arity of a tuple.
+ <c><![CDATA[erl_size()]]></c> will do the same thing, but it checks that
+ the argument really is a tuple.
+ <c><![CDATA[erl_element(index,tuple)]]></c> returns the element
+ corresponding to a given position in the tuple. </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_mk_uint(n)</nametext></name>
+ <fsummary>Creates an unsigned integer</fsummary>
+ <type>
+ <v>unsigned int n;</v>
+ </type>
+ <desc>
+ <p>Creates an Erlang unsigned integer.</p>
+ <p><c><![CDATA[n]]></c> is a value to be converted to an Erlang
+ unsigned integer.</p>
+ <p></p>
+ <p>The function returns an Erlang unsigned integer object with
+ the value specified in <c><![CDATA[n]]></c>.</p>
+ <p><c><![CDATA[ERL_INT_UVALUE(t)]]></c> can be used to retrieve the
+ value from an Erlang unsigned integer.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_mk_var(name)</nametext></name>
+ <fsummary>Creates an Erlang variable</fsummary>
+ <type>
+ <v>char *name;</v>
+ </type>
+ <desc>
+ <p>This function creates an unbound Erlang variable. The
+ variable can later be bound through pattern matching or assignment.</p>
+ <p><c><![CDATA[name]]></c> specifies a name for the variable.</p>
+ <p>The function returns an Erlang variable object with the
+ name <c><![CDATA[name]]></c>. </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_print_term(stream, term)</nametext></name>
+ <fsummary>Prints an Erlang term</fsummary>
+ <type>
+ <v>FILE *stream;</v>
+ <v>ETERM *term;</v>
+ </type>
+ <desc>
+ <p>This function prints the specified Erlang term to the given
+ output stream.</p>
+ <p><c><![CDATA[stream]]></c> indicates where the function should send its
+ output.</p>
+ <p><c><![CDATA[term]]></c> is the Erlang term to print.</p>
+ <p>The function returns the number of characters written, or a
+ negative value if there was an error.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>void</ret><nametext>erl_set_compat_rel(release_number)</nametext></name>
+ <fsummary>Set the erl_interface library in compatibility mode</fsummary>
+ <type>
+ <v>unsigned release_number;</v>
+ </type>
+ <desc>
+ <marker id="erl_set_compat_rel"></marker>
+ <p>By default, the <c><![CDATA[erl_interface]]></c> library is only guaranteed
+ to be compatible with other Erlang/OTP components from the same
+ release as the <c><![CDATA[erl_interface]]></c> library itself. For example,
+ <c><![CDATA[erl_interface]]></c> from the OTP R10 release is not compatible
+ with an Erlang emulator from the OTP R9 release by default.</p>
+ <p>A call to <c><![CDATA[erl_set_compat_rel(release_number)]]></c> sets the
+ <c><![CDATA[erl_interface]]></c> library in compatibility mode of release
+ <c><![CDATA[release_number]]></c>. Valid range of <c><![CDATA[release_number]]></c>
+ is [7, current release]. This makes it possible to
+ communicate with Erlang/OTP components from earlier releases.</p>
+ <note>
+ <p>If this function is called, it may only be called once
+ directly after the call to the
+ <seealso marker="#erl_init">erl_init()</seealso> function.</p>
+ </note>
+ <warning>
+ <p>You may run into trouble if this feature is used
+ carelessly. Always make sure that all communicating
+ components are either from the same Erlang/OTP release, or
+ from release X and release Y where all components
+ from release Y are in compatibility mode of release X.</p>
+ </warning>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_size(term)</nametext></name>
+ <fsummary>Return the arity of a tuple or binary</fsummary>
+ <type>
+ <v>ETERM *term;</v>
+ </type>
+ <desc>
+ <p>Returns the arity of an Erlang tuple, or the
+ number of bytes in an Erlang binary object. </p>
+ <p><c><![CDATA[term]]></c> is an Erlang tuple or an Erlang binary object.</p>
+ <p>The function returns the size of <c><![CDATA[term]]></c> as described
+ above, or -1 if <c><![CDATA[term]]></c> is not one of the two supported
+ types. </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_tl(list)</nametext></name>
+ <fsummary>Extracts the tail from a list</fsummary>
+ <type>
+ <v>ETERM *list;</v>
+ </type>
+ <desc>
+ <p>Extracts the tail from a list.</p>
+ <p><c><![CDATA[list]]></c> is an Erlang term containing a list.</p>
+ <p>The function returns an Erlang list corresponding to the
+ original list minus the first element, or NULL pointer if
+ <c><![CDATA[list]]></c> was not a list.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_var_content(term, name)</nametext></name>
+ <fsummary>Extracts the content of a variable</fsummary>
+ <type>
+ <v>ETERM *term;</v>
+ <v>char *name;</v>
+ </type>
+ <desc>
+ <p>This function returns the contents of the specified
+ variable in an Erlang term.
+ </p>
+ <p><c><![CDATA[term]]></c> is an Erlang term. In order for this function
+ to succeed, <c><![CDATA[term]]></c> must be an Erlang variable with the
+ specified name, or it must be an Erlang list or tuple
+ containing a variable with the specified name. Other Erlang
+ types cannot contain variables.</p>
+ <p><c><![CDATA[name]]></c> is the name of an Erlang variable.</p>
+ <p>Returns the Erlang object corresponding to the value of
+ <c><![CDATA[name]]></c> in <c><![CDATA[term]]></c>. If no variable with the name
+ <c><![CDATA[name]]></c> was found in <c><![CDATA[term]]></c>, or if <c><![CDATA[term]]></c> is
+ not a valid Erlang term, NULL is returned.</p>
+ </desc>
+ </func>
+ </funcs>
+</cref>
+
diff --git a/lib/erl_interface/doc/src/erl_format.xml b/lib/erl_interface/doc/src/erl_format.xml
new file mode 100644
index 0000000000..5699485845
--- /dev/null
+++ b/lib/erl_interface/doc/src/erl_format.xml
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE cref SYSTEM "cref.dtd">
+
+<cref>
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>erl_format</title>
+ <prepared>Torbj&ouml;rn T&ouml;rnkvist</prepared>
+ <responsible>Torbj&ouml;rn T&ouml;rnkvist</responsible>
+ <docno></docno>
+ <approved>Bjarne D&auml;cker</approved>
+ <checked>Torbj&ouml;rn T&ouml;rnkvist</checked>
+ <date>961016</date>
+ <rev>A</rev>
+ <file>erl_format.sgml</file>
+ </header>
+ <lib>erl_format</lib>
+ <libsummary>Create and Match Erlang Terms</libsummary>
+ <description>
+ <p>This module contains two routines - one general function for
+ creating Erlang terms and one for pattern matching Erlang terms.</p>
+ </description>
+ <funcs>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_format(FormatStr, ... )</nametext></name>
+ <fsummary>Creates an Erlang term</fsummary>
+ <type>
+ <v>char *FormatStr;</v>
+ </type>
+ <desc>
+ <p>This is a general function for creating Erlang terms using
+ a format specifier and a corresponding set of arguments, much
+ in the way <c><![CDATA[printf()]]></c> works.</p>
+ <p><c><![CDATA[FormatStr]]></c> is a format specification string. The set
+ of valid format specifiers is as follows:</p>
+ <list type="bulleted">
+ <item>
+ <p>~i - Integer</p>
+ </item>
+ <item>
+ <p>~f - Floating point</p>
+ </item>
+ <item>
+ <p>~a - Atom</p>
+ </item>
+ <item>
+ <p>~s - String</p>
+ </item>
+ <item>
+ <p>~w - Arbitrary Erlang term</p>
+ </item>
+ </list>
+ <p>For each format specifier that appears in <c><![CDATA[FormatStr]]></c>,
+ there must be a corresponding argument following
+ <c><![CDATA[FormatStr]]></c>. An Erlang term is built according to the
+ <c><![CDATA[FormatStr]]></c> with values and Erlang terms substituted from
+ the corresponding arguments and according to the individual
+ format specifiers. For example:</p>
+ <code type="none"><![CDATA[
+erl_format("[{name,~a},{age,~i},{data,~w}]",
+ "madonna",
+ 21,
+ erl_format("[{adr,~s,~i}]","E-street",42));
+ ]]></code>
+ <p>This will create an <c><![CDATA[(ETERM *)]]></c> structure corresponding
+ to the Erlang term:
+ <c><![CDATA[[{name,madonna},{age,21},{data,[{adr,"E-street",42}]}]]]></c></p>
+ <p>The function returns an Erlang term, or NULL if
+ <c><![CDATA[FormatStr]]></c> does not describe a valid Erlang term.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_match(Pattern, Term)</nametext></name>
+ <fsummary>Performs pattern matching</fsummary>
+ <type>
+ <v>ETERM *Pattern,*Term;</v>
+ </type>
+ <desc>
+ <p>This function is used to perform pattern matching similar
+ to that done in Erlang. Refer to an Erlang manual for matching
+ rules and more examples.</p>
+ <p><c><![CDATA[Pattern]]></c> is an Erlang term, possibly containing unbound
+ variables. </p>
+ <p><c><![CDATA[Term]]></c> is an Erlang term that we wish to match against
+ <c><![CDATA[Pattern]]></c>.</p>
+ <p><c><![CDATA[Term]]></c> and <c><![CDATA[Pattern]]></c> are compared, and any
+ unbound variables in <c><![CDATA[Pattern]]></c> are bound to corresponding
+ values in <c><![CDATA[Term]]></c>. </p>
+ <p>If <c><![CDATA[Term]]></c> and <c><![CDATA[Pattern]]></c> can be matched, the
+ function returns a non-zero value and binds any unbound
+ variables in <c><![CDATA[Pattern]]></c>. If <c><![CDATA[Term]]></c><c><![CDATA[Pattern]]></c> do
+ not match, the function returns 0. For example:</p>
+ <code type="none"><![CDATA[
+ETERM *term, *pattern, *pattern2;
+term1 = erl_format("{14,21}");
+term2 = erl_format("{19,19}");
+pattern1 = erl_format("{A,B}");
+pattern2 = erl_format("{F,F}");
+if (erl_match(pattern1, term1)) {
+ /* match succeeds:
+ * A gets bound to 14,
+ * B gets bound to 21
+ */
+ ...
+}
+if (erl_match(pattern2, term1)) {
+ /* match fails because F cannot be
+ * bound to two separate values, 14 and 21
+ */
+ ...
+}
+if (erl_match(pattern2, term2)) {
+ /* match succeeds and F gets bound to 19 */
+ ...
+}
+ ]]></code>
+ <p><c><![CDATA[erl_var_content()]]></c> can be used to retrieve the
+ content of any variables bound as a result of a call to
+ <c><![CDATA[erl_match()]]></c>.</p>
+ </desc>
+ </func>
+ </funcs>
+</cref>
+
diff --git a/lib/erl_interface/doc/src/erl_global.xml b/lib/erl_interface/doc/src/erl_global.xml
new file mode 100644
index 0000000000..8f9a354b4f
--- /dev/null
+++ b/lib/erl_interface/doc/src/erl_global.xml
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE cref SYSTEM "cref.dtd">
+
+<cref>
+ <header>
+ <copyright>
+ <year>1998</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>erl_global</title>
+ <prepared>Gordon Beaton</prepared>
+ <responsible>Gordon Beaton</responsible>
+ <docno></docno>
+ <approved>Gordon Beaton</approved>
+ <checked>Gordon Beaton</checked>
+ <date>980703</date>
+ <rev>A</rev>
+ <file>erl_global.sgml</file>
+ </header>
+ <lib>erl_global</lib>
+ <libsummary>Access globally registered names</libsummary>
+ <description>
+ <p>This module provides support for registering, looking
+ up and unregistering names in the Erlang Global module. For more
+ information, see the description of Global in the reference manual.</p>
+ <p>Note that the functions below perform an RPC using an open file
+ descriptor provided by the caller. This file descriptor must
+ not be used for other traffic during the global operation or the
+ function may receive unexpected data and fail.</p>
+ </description>
+ <funcs>
+ <func>
+ <name><ret>char **</ret><nametext>erl_global_names(fd,count)</nametext></name>
+ <fsummary>Obtain list of Global names</fsummary>
+ <type>
+ <v>int fd;</v>
+ <v>int *count;</v>
+ </type>
+ <desc>
+ <p>Retrieve a list of all known global names.
+ </p>
+ <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.
+ </p>
+ <p><c><![CDATA[count]]></c> is the address of an integer, or NULL. If
+ <c><![CDATA[count]]></c> is not NULL, it will be set by the function to
+ the number of names found.
+ </p>
+ <p>On success, the function returns an array of strings, each
+ containing a single registered name, and sets <c><![CDATA[count]]></c> to
+ the number of names found. The array is terminated
+ by a single NULL pointer. On failure, the function returns
+ NULL and <c><![CDATA[count]]></c> is not modified.
+ </p>
+ <note>
+ <p>It is the caller's responsibility to free the array
+ afterwards. It has been allocated by the function with a
+ single call to <c><![CDATA[malloc()]]></c>, so a single <c><![CDATA[free()]]></c> is
+ all that is necessary.</p>
+ </note>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_global_register(fd,name,pid)</nametext></name>
+ <fsummary>Register a name in Global</fsummary>
+ <type>
+ <v>int fd;</v>
+ <v>const char *name;</v>
+ <v>ETERM *pid;</v>
+ </type>
+ <desc>
+ <p>This function registers a name in Global.
+ </p>
+ <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.
+ </p>
+ <p><c><![CDATA[name]]></c> is the name to register in Global.
+ </p>
+ <p><c><![CDATA[pid]]></c> is the pid that should be associated with
+ <c><![CDATA[name]]></c>. This is the value that Global will return when
+ processes request the location of <c><![CDATA[name]]></c>.
+ </p>
+ <p>The function returns 0 on success, or -1 on failure.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_global_unregister(fd,name)</nametext></name>
+ <fsummary>Unregister a name in Global</fsummary>
+ <type>
+ <v>int fd;</v>
+ <v>const char *name;</v>
+ </type>
+ <desc>
+ <p>This function unregisters a name from Global.
+ </p>
+ <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.
+ </p>
+ <p><c><![CDATA[name]]></c> is the name to unregister from Global.
+ </p>
+ <p>The function returns 0 on success, or -1 on failure.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_global_whereis(fd,name,node)</nametext></name>
+ <fsummary>Look up a name in global</fsummary>
+ <type>
+ <v>int fd;</v>
+ <v>const char *name;</v>
+ <v>char *node;</v>
+ </type>
+ <desc>
+ <p><c><![CDATA[fd]]></c> is an open descriptor to an Erlang connection.
+ </p>
+ <p><c><![CDATA[name]]></c> is the name that is to be looked up in Global.
+ </p>
+ <p>If <c><![CDATA[node]]></c> is not NULL, it is a pointer to a buffer
+ where the function can fill in the name of the node where
+ <c><![CDATA[name]]></c> is found. <c><![CDATA[node]]></c> can be passed directly to
+ <c><![CDATA[erl_connect()]]></c> if necessary.
+ </p>
+ <p>On success, the function returns an Erlang Pid containing the address
+ of the given name, and node will be initialized to
+ the nodename where <c><![CDATA[name]]></c> is found. On failure NULL will be
+ returned and <c><![CDATA[node]]></c> will not be modified.</p>
+ </desc>
+ </func>
+ </funcs>
+</cref>
+
diff --git a/lib/erl_interface/doc/src/erl_interface.xml b/lib/erl_interface/doc/src/erl_interface.xml
new file mode 100644
index 0000000000..850a4127f4
--- /dev/null
+++ b/lib/erl_interface/doc/src/erl_interface.xml
@@ -0,0 +1,625 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>The Erl_Interface Library</title>
+ <prepared>Torbj&ouml;rn T&ouml;rnkvist</prepared>
+ <responsible>Torbj&ouml;rn T&ouml;rnkvist</responsible>
+ <docno></docno>
+ <approved>Bjarne D&auml;cker</approved>
+ <checked>K.Lundin</checked>
+ <date>990113</date>
+ <rev>A</rev>
+ <file>erl_interface.sgml</file>
+ </header>
+ <p>The Erl_Interface library contains functions. which help you
+ integrate programs written in C and Erlang. The functions in
+ Erl_Interface support the following:</p>
+ <list type="bulleted">
+ <item>manipulation of data represented as Erlang data types</item>
+ <item>conversion of data between C and Erlang formats</item>
+ <item>encoding and decoding of Erlang data types for transmission or storage</item>
+ <item>communication between C nodes and Erlang processes</item>
+ <item>backup and restore of C node state to and from Mnesia</item>
+ </list>
+ <p>In the following sections, these topics are described:</p>
+ <list type="bulleted">
+ <item>compiling your code for use with Erl_Interface</item>
+ <item>initializing Erl_Interface</item>
+ <item>encoding, decoding, and sending Erlang terms</item>
+ <item>building terms and patterns</item>
+ <item>pattern matching</item>
+ <item>connecting to a distributed Erlang node</item>
+ <item>using EPMD</item>
+ <item>sending and receiving Erlang messages</item>
+ <item>remote procedure calls</item>
+ <item>global names</item>
+ <item>the registry</item>
+ </list>
+
+ <section>
+ <title>Compiling and Linking Your Code</title>
+ <p>In order to use any of the Erl_Interface functions, include the
+ following lines in your code:</p>
+ <code type="none"><![CDATA[
+#include "erl_interface.h"
+#include "ei.h" ]]></code>
+ <p>Determine where the top directory of your OTP installation is. You
+ can find this out by starting Erlang and entering the following
+ command at the Eshell prompt:</p>
+ <code type="none"><![CDATA[
+Eshell V4.7.4 (abort with ^G)
+1> code:root_dir().
+/usr/local/otp ]]></code>
+ <p>To compile your code, make sure that your C compiler knows where
+ to find <c><![CDATA[erl_interface.h]]></c> by specifying an appropriate <c><![CDATA[-I]]></c>
+ argument on the command line, or by adding it to the <c><![CDATA[CFLAGS]]></c>
+ definition in your <c><![CDATA[Makefile]]></c>. The correct value for this path is
+ <c><![CDATA[$OTPROOT/lib/erl_interface]]></c><em>Vsn</em><c><![CDATA[/include]]></c>, where <c><![CDATA[$OTPROOT]]></c> is the path
+ reported by <c><![CDATA[code:root_dir/0]]></c> in the above example, and <em>Vsn</em> is
+ the version of the Erl_interface application, for example
+ <c><![CDATA[erl_interface-3.2.3]]></c></p>
+ <code type="none"><![CDATA[
+$ cc -c -I/usr/local/otp/lib/erl_interface-3.2.3/include myprog.c ]]></code>
+ <p>When linking, you will need to specify the path to
+ <c><![CDATA[liberl_interface.a]]></c> and <c><![CDATA[libei.a]]></c> with
+ <c><![CDATA[-L$OTPROOT/lib/erl_interface-3.2.3/lib]]></c>, and you will need to specify the
+ name of the libraries with <c><![CDATA[-lerl_interface -lei]]></c>. You can do
+ this on the command line or by adding the flags to the <c><![CDATA[LDFLAGS]]></c>
+ definition in your <c><![CDATA[Makefile]]></c>.</p>
+ <code type="none"><![CDATA[
+$ ld -L/usr/local/otp/lib/erl_interface-3.2.3/
+ lib myprog.o -lerl_interface -lei -o myprog ]]></code>
+ <p>Also, on some systems it may be necessary to link with some
+ additional libraries (e.g. <c><![CDATA[libnsl.a]]></c> and <c><![CDATA[libsocket.a]]></c> on
+ Solaris, or <c><![CDATA[wsock32.lib]]></c> on Windows) in order to use the
+ communication facilities of Erl_Interface.</p>
+ <p>If you are using Erl_Interface functions in a threaded
+ application based on POSIX threads or Solaris threads, then
+ Erl_Interface needs access to some of the synchronization
+ facilities in your threads package, and you will need to specify
+ additional compiler flags in order to indicate which of the packages
+ you are using. Define <c><![CDATA[_REENTRANT]]></c> and either <c><![CDATA[STHREADS]]></c> or
+ <c><![CDATA[PTHREADS]]></c>. The default is to use POSIX threads if
+ <c><![CDATA[_REENTRANT]]></c> is specified.</p>
+ <p>Note that both single threaded and default versions of the Erl_interface
+ and Ei libraries are provided. (The single threaded versions are named
+ <c><![CDATA[liberl_interface_st]]></c> and <c><![CDATA[libei_st]]></c>). Whether the default
+ versions of the libraries have support for threads or not is determined by if
+ the platform in question has support for POSIX or Solaris threads. To check this,
+ have a look in the <c><![CDATA[eidefs.mk]]></c> file in the erl_interface src directory.</p>
+ </section>
+
+ <section>
+ <title>Initializing the erl_interface Library</title>
+ <p>Before calling any of the other Erl_Interface functions, you
+ must call <c><![CDATA[erl_init()]]></c> exactly once to initialize the library.
+ <c><![CDATA[erl_init()]]></c> takes two arguments, however the arguments are no
+ longer used by Erl_Interface, and should therefore be specified
+ as <c><![CDATA[erl_init(NULL,0)]]></c>.</p>
+ </section>
+
+ <section>
+ <title>Encoding, Decoding and Sending Erlang Terms</title>
+ <p>Data sent between distributed Erlang nodes is encoded in the
+ Erlang external format. Consequently, you have to encode and decode
+ Erlang terms into byte streams if you want to use the distribution
+ protocol to communicate between a C program and Erlang. </p>
+ <p>The Erl_Interface library supports this activity. It has a
+ number of C functions which create and manipulate Erlang data
+ structures. The library also contains an encode and a decode function.
+ The example below shows how to create and encode an Erlang tuple
+ <c><![CDATA[{tobbe,3928}]]></c>:</p>
+ <code type="none"><![CDATA[
+
+ETERM *arr[2], *tuple;
+char buf[BUFSIZ];
+int i;
+
+arr[0] = erl_mk_atom("tobbe");
+arr[1] = erl_mk_integer(3928);
+tuple = erl_mk_tuple(arr, 2);
+i = erl_encode(tuple, buf); ]]></code>
+ <p>Alternatively, you can use <c><![CDATA[erl_send()]]></c> and
+ <c><![CDATA[erl_receive_msg]]></c>, which handle the encoding and decoding of
+ messages transparently.</p>
+ <p>Refer to the Reference Manual for a complete description of the
+ following modules:</p>
+ <list type="bulleted">
+ <item>the <c><![CDATA[erl_eterm]]></c> module for creating Erlang terms</item>
+ <item>the <c><![CDATA[erl_marshal]]></c> module for encoding and decoding routines.</item>
+ </list>
+ </section>
+
+ <section>
+ <title>Building Terms and Patterns</title>
+ <p>The previous example can be simplified by using
+ <c><![CDATA[erl_format()]]></c> to create an Erlang term.</p>
+ <code type="none"><![CDATA[
+
+ETERM *ep;
+ep = erl_format("{~a,~i}", "tobbe", 3928); ]]></code>
+ <p>Refer to the Reference Manual, the <c><![CDATA[erl_format]]></c> module, for a
+ full description of the different format directives. The following
+ example is more complex:</p>
+ <code type="none"><![CDATA[
+
+ETERM *ep;
+ep = erl_format("[{name,~a},{age,~i},{data,~w}]",
+ "madonna",
+ 21,
+ erl_format("[{adr,~s,~i}]", "E-street", 42));
+erl_free_compound(ep); ]]></code>
+ <p>As in previous examples, it is your responsibility to free the
+ memory allocated for Erlang terms. In this example,
+ <c><![CDATA[erl_free_compound()]]></c> ensures that the complete term pointed to
+ by <c><![CDATA[ep]]></c> is released. This is necessary, because the pointer from
+ the second call to <c><![CDATA[erl_format()]]></c> is lost. </p>
+ <p>The following
+ example shows a slightly different solution:</p>
+ <code type="none"><![CDATA[
+
+ETERM *ep,*ep2;
+ep2 = erl_format("[{adr,~s,~i}]","E-street",42);
+ep = erl_format("[{name,~a},{age,~i},{data,~w}]",
+ "madonna", 21, ep2);
+erl_free_term(ep);
+erl_free_term(ep2); ]]></code>
+ <p>In this case, you free the two terms independently. The order in
+ which you free the terms <c><![CDATA[ep]]></c> and <c><![CDATA[ep2]]></c> is not important,
+ because the Erl_Interface library uses reference counting to
+ determine when it is safe to actually remove objects. </p>
+ <p>If you are not sure whether you have freed the terms properly, you
+ can use the following function to see the status of the fixed term
+ allocator:</p>
+ <code type="none"><![CDATA[
+long allocated, freed;
+
+erl_eterm_statistics(&allocated,&freed);
+printf("currently allocated blocks: %ld\
+",allocated);
+printf("length of freelist: %ld\
+",freed);
+
+/* really free the freelist */
+erl_eterm_release();
+ ]]></code>
+ <p>Refer to the Reference Manual, the <c><![CDATA[erl_malloc]]></c> module for more
+ information.</p>
+ </section>
+
+ <section>
+ <title>Pattern Matching</title>
+ <p>An Erlang pattern is a term that may contain unbound variables or
+ <c><![CDATA["do not care"]]></c> symbols. Such a pattern can be matched against a
+ term and, if the match is successful, any unbound variables in the
+ pattern will be bound as a side effect. The content of a bound
+ variable can then be retrieved.</p>
+ <code type="none"><![CDATA[
+
+ETERM *pattern;
+pattern = erl_format("{madonna,Age,_}"); ]]></code>
+ <p><c><![CDATA[erl_match()]]></c> is used to perform pattern matching. It takes a
+ pattern and a term and tries to match them. As a side effect any unbound
+ variables in the pattern will be bound. In the following example, we
+ create a pattern with a variable <em>Age</em> which appears at two
+ positions in the tuple. The pattern match is performed as follows:</p>
+ <list type="ordered">
+ <item><c><![CDATA[erl_match()]]></c> will bind the contents of
+ <em>Age</em> to <em>21</em> the first time it reaches the variable</item>
+ <item>the second occurrence of <em>Age</em> will cause a test for
+ equality between the terms since <em>Age</em> is already bound to
+ <em>21</em>. Since <em>Age</em> is bound to 21, the equality test will
+ succeed and the match continues until the end of the pattern.</item>
+ <item>if the end of the pattern is reached, the match succeeds and you
+ can retrieve the contents of the variable</item>
+ </list>
+ <code type="none"><![CDATA[
+ETERM *pattern,*term;
+pattern = erl_format("{madonna,Age,Age}");
+term = erl_format("{madonna,21,21}");
+if (erl_match(pattern, term)) {
+ fprintf(stderr, "Yes, they matched: Age = ");
+ ep = erl_var_content(pattern, "Age");
+ erl_print_term(stderr, ep);
+ fprintf(stderr,"\
+");
+ erl_free_term(ep);
+}
+erl_free_term(pattern);
+erl_free_term(term); ]]></code>
+ <p>Refer to the Reference Manual, the <c><![CDATA[erl_match()]]></c> function for
+ more information.</p>
+ </section>
+
+ <section>
+ <title>Connecting to a Distributed Erlang Node</title>
+ <p>In order to connect to a distributed Erlang node you need to first
+ initialize the connection routine with <c><![CDATA[erl_connect_init()]]></c>,
+ which stores information such as the host name, node name, and IP
+ address for later use:</p>
+ <code type="none"><![CDATA[
+int identification_number = 99;
+int creation=1;
+char *cookie="a secret cookie string"; /* An example */
+erl_connect_init(identification_number, cookie, creation); ]]></code>
+ <p>Refer to the Reference Manual, the <c><![CDATA[erl_connect]]></c> module for more information.</p>
+ <p>After initialization, you set up the connection to the Erlang node.
+ Use <c><![CDATA[erl_connect()]]></c> to specify the Erlang node you want to
+ connect to. The following example sets up the connection and should
+ result in a valid socket file descriptor:</p>
+ <code type="none"><![CDATA[
+int sockfd;
+char *nodename="[email protected]"; /* An example */
+if ((sockfd = erl_connect(nodename)) < 0)
+ erl_err_quit("ERROR: erl_connect failed"); ]]></code>
+ <p><c><![CDATA[erl_err_quit()]]></c> prints the specified string and terminates
+ the program. Refer to the Reference Manual, the <c><![CDATA[erl_error()]]></c>
+ function for more information.</p>
+ </section>
+
+ <section>
+ <title>Using EPMD</title>
+ <p><c><![CDATA[Epmd]]></c> is the Erlang Port Mapper Daemon. Distributed Erlang nodes
+ register with <c><![CDATA[epmd]]></c> on the localhost to indicate to other nodes that
+ they exist and can accept connections. <c><![CDATA[Epmd]]></c> maintains a register of
+ node and port number information, and when a node wishes to connect to
+ another node, it first contacts <c><![CDATA[epmd]]></c> in order to find out the correct
+ port number to connect to.</p>
+ <p>When you use <c><![CDATA[erl_connect()]]></c> to connect to an Erlang node, a
+ connection is first made to <c><![CDATA[epmd]]></c> and, if the node is known, a
+ connection is then made to the Erlang node.</p>
+ <p>C nodes can also register themselves with <c><![CDATA[epmd]]></c> if they want other
+ nodes in the system to be able to find and connect to them.</p>
+ <p>Before registering with <c><![CDATA[epmd]]></c>, you need to first create a listen socket
+ and bind it to a port. Then:</p>
+ <code type="none"><![CDATA[
+int pub;
+
+pub = erl_publish(port); ]]></code>
+ <p><c><![CDATA[pub]]></c> is a file descriptor now connected to <c><![CDATA[epmd]]></c>. <c><![CDATA[Epmd]]></c>
+ monitors the other end of the connection, and if it detects that the
+ connection has been closed, the node will be unregistered. So, if you
+ explicitly close the descriptor or if your node fails, it will be
+ unregistered from <c><![CDATA[epmd]]></c>.</p>
+ <p>Be aware that on some systems (such as VxWorks), a failed node will
+ not be detected by this mechanism since the operating system does not
+ automatically close descriptors that were left open when the node
+ failed. If a node has failed in this way, <c><![CDATA[epmd]]></c> will prevent you from
+ registering a new node with the old name, since it thinks that the old
+ name is still in use. In this case, you must unregister the name
+ explicitly:</p>
+ <code type="none"><![CDATA[
+erl_unpublish(node); ]]></code>
+ <p>This will cause <c><![CDATA[epmd]]></c> to close the connection from the far end. Note
+ that if the name was in fact still in use by a node, the results of
+ this operation are unpredictable. Also, doing this does not cause the
+ local end of the connection to close, so resources may be consumed.</p>
+ </section>
+
+ <section>
+ <title>Sending and Receiving Erlang Messages</title>
+ <p>Use one of the following two functions to send messages:</p>
+ <list type="bulleted">
+ <item><c><![CDATA[erl_send()]]></c></item>
+ <item><c><![CDATA[erl_reg_send()]]></c></item>
+ </list>
+ <p>As in Erlang, it is possible to send messages to a
+ <em>Pid</em> or to a registered name. It is easier to send a
+ message to a registered name because it avoids the problem of finding
+ a suitable <em>Pid</em>.</p>
+ <p>Use one of the following two functions to receive messages:</p>
+ <list type="bulleted">
+ <item><c><![CDATA[erl_receive()]]></c></item>
+ <item><c><![CDATA[erl_receive_msg()]]></c></item>
+ </list>
+ <p><c><![CDATA[erl_receive()]]></c> receives the message into a buffer, while
+ <c><![CDATA[erl_receive_msg()]]></c> decodes the message into an Erlang term. </p>
+
+ <section>
+ <title>Example of Sending Messages</title>
+ <p>In the following example, <c><![CDATA[{Pid, hello_world}]]></c> is
+ sent to a registered process <c><![CDATA[my_server]]></c>. The message is encoded
+ by <c><![CDATA[erl_send()]]></c>:</p>
+ <code type="none"><![CDATA[
+extern const char *erl_thisnodename(void);
+extern short erl_thiscreation(void);
+#define SELF(fd) erl_mk_pid(erl_thisnodename(),fd,0,erl_thiscreation())
+ETERM *arr[2], *emsg;
+int sockfd, creation=1;
+
+arr[0] = SELF(sockfd);
+arr[1] = erl_mk_atom("Hello world");
+emsg = erl_mk_tuple(arr, 2);
+
+erl_reg_send(sockfd, "my_server", emsg);
+erl_free_term(emsg); ]]></code>
+ <p>The first element of the tuple that is sent is your own
+ <em>Pid</em>. This enables <c><![CDATA[my_server]]></c> to reply. Refer to the
+ Reference Manual, the <c><![CDATA[erl_connect]]></c> module for more information
+ about send primitives.</p>
+ </section>
+
+ <section>
+ <title>Example of Receiving Messages</title>
+ <p>In this example <c><![CDATA[{Pid, Something}]]></c> is received. The
+ received Pid is then used to return <c><![CDATA[{goodbye,Pid}]]></c></p>
+ <code type="none"><![CDATA[
+ETERM *arr[2], *answer;
+int sockfd,rc;
+char buf[BUFSIZE];
+ErlMessage emsg;
+
+if ((rc = erl_receive_msg(sockfd , buf, BUFSIZE, &emsg)) == ERL_MSG) {
+ arr[0] = erl_mk_atom("goodbye");
+ arr[1] = erl_element(1, emsg.msg);
+ answer = erl_mk_tuple(arr, 2);
+ erl_send(sockfd, arr[1], answer);
+ erl_free_term(answer);
+ erl_free_term(emsg.msg);
+ erl_free_term(emsg.to);
+}
+} ]]></code>
+ <p>In order to provide robustness, a distributed Erlang node
+ occasionally polls all its connected neighbours in an attempt to
+ detect failed nodes or communication links. A node which receives such
+ a message is expected to respond immediately with an <c><![CDATA[ERL_TICK]]></c> message.
+ This is done automatically by <c><![CDATA[erl_receive()]]></c>, however when this
+ has occurred <c><![CDATA[erl_receive]]></c> returns <c><![CDATA[ERL_TICK]]></c> to the caller
+ without storing a message into the <c><![CDATA[ErlMessage]]></c> structure.</p>
+ <p>When a message has been received, it is the caller's responsibility
+ to free the received message <c><![CDATA[emsg.msg]]></c> as well as <c><![CDATA[emsg.to]]></c>
+ or <c><![CDATA[emsg.from]]></c>, depending on the type of message received.</p>
+ <p>Refer to the Reference Manual for additional information about the
+ following modules:</p>
+ <list type="bulleted">
+ <item><c><![CDATA[erl_connect]]></c></item>
+ <item><c><![CDATA[erl_eterm]]></c>.</item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Remote Procedure Calls</title>
+ <p>An Erlang node acting as a client to another Erlang node
+ typically sends a request and waits for a reply. Such a request is
+ included in a function call at a remote node and is called a remote
+ procedure call. The following example shows how the
+ Erl_Interface library supports remote procedure calls:</p>
+ <code type="none"><![CDATA[
+
+char modname[]=THE_MODNAME;
+ETERM *reply,*ep;
+ep = erl_format("[~a,[]]", modname);
+if (!(reply = erl_rpc(fd, "c", "c", ep)))
+ erl_err_msg("<ERROR> when compiling file: %s.erl !\
+", modname);
+erl_free_term(ep);
+ep = erl_format("{ok,_}");
+if (!erl_match(ep, reply))
+ erl_err_msg("<ERROR> compiler errors !\
+");
+erl_free_term(ep);
+erl_free_term(reply); ]]></code>
+ <p><c><![CDATA[c:c/1]]></c> is called to compile the specified module on the
+ remote node. <c><![CDATA[erl_match()]]></c> checks that the compilation was
+ successful by testing for the expected <c><![CDATA[ok]]></c>.</p>
+ <p>Refer to the Reference Manual, the <c><![CDATA[erl_connect]]></c> module for
+ more information about <c><![CDATA[erl_rpc()]]></c>, and its companions
+ <c><![CDATA[erl_rpc_to()]]></c> and <c><![CDATA[erl_rpc_from()]]></c>.</p>
+ </section>
+
+ <section>
+ <title>Using Global Names</title>
+ <p>A C node has access to names registered through the Erlang Global
+ module. Names can be looked up, allowing the C node to send messages
+ to named Erlang services. C nodes can also register global names,
+ allowing them to provide named services to Erlang processes or other C
+ nodes. </p>
+ <p>Erl_Interface does not provide a native implementation of the global
+ service. Instead it uses the global services provided by a "nearby"
+ Erlang node. In order to use the services described in this section,
+ it is necessary to first open a connection to an Erlang node.</p>
+ <p>To see what names there are:</p>
+ <code type="none"><![CDATA[
+char **names;
+int count;
+int i;
+
+names = erl_global_names(fd,&count);
+
+if (names)
+ for (i=0; i<count; i++)
+ printf("%s\
+",names[i]);
+
+free(names); ]]></code>
+ <p><c><![CDATA[erl_global_names()]]></c> allocates and returns a buffer containing
+ all the names known to global. <c><![CDATA[count]]></c> will be initialized to
+ indicate how many names are in the array. The array of strings in
+ names is terminated by a NULL pointer, so it is not necessary to use
+ <c><![CDATA[count]]></c> to determine when the last name is reached.</p>
+ <p>It is the caller's responsibility to free the array.
+ <c><![CDATA[erl_global_names()]]></c> allocates the array and all of the strings
+ using a single call to <c><![CDATA[malloc()]]></c>, so <c><![CDATA[free(names)]]></c> is all
+ that is necessary.</p>
+ <p>To look up one of the names:</p>
+ <code type="none"><![CDATA[
+ETERM *pid;
+char node[256];
+
+pid = erl_global_whereis(fd,"schedule",node); ]]></code>
+ <p>If <c><![CDATA["schedule"]]></c> is known to global, an Erlang pid is returned
+ that can be used to send messages to the schedule service.
+ Additionally, <c><![CDATA[node]]></c> will be initialized to contain the name of
+ the node where the service is registered, so that you can make a
+ connection to it by simply passing the variable to <c><![CDATA[erl_connect()]]></c>.</p>
+ <p>Before registering a name, you should already have registered your
+ port number with <c><![CDATA[epmd]]></c>. This is not strictly necessary, but if you
+ neglect to do so, then other nodes wishing to communicate with your
+ service will be unable to find or connect to your process.</p>
+ <p>Create a pid that Erlang processes can use to communicate with your
+ service:</p>
+ <code type="none"><![CDATA[
+ETERM *pid;
+
+pid = erl_mk_pid(thisnode,14,0,0);
+erl_global_register(fd,servicename,pid); ]]></code>
+ <p>After registering the name, you should use <c><![CDATA[erl_accept()]]></c> to wait for
+ incoming connections.</p>
+ <p>Do not forget to free <c><![CDATA[pid]]></c> later with <c><![CDATA[erl_free_term()]]></c>!</p>
+ <p>To unregister a name:</p>
+ <code type="none"><![CDATA[
+erl_global_unregister(fd,servicename); ]]></code>
+ </section>
+
+ <section>
+ <title>The Registry</title>
+ <p>This section describes the use of the registry, a simple mechanism
+ for storing key-value pairs in a C-node, as well as backing them up or
+ restoring them from a Mnesia table on an Erlang node. More detailed
+ information about the individual API functions can be found in the
+ Reference Manual.</p>
+ <p>Keys are strings, i.e. 0-terminated arrays of characters, and values
+ are arbitrary objects. Although integers and floating point numbers
+ are treated specially by the registry, you can store strings or binary
+ objects of any type as pointers.</p>
+ <p>To start, you need to open a registry:</p>
+ <code type="none"><![CDATA[
+ei_reg *reg;
+
+reg = ei_reg_open(45); ]]></code>
+ <p>The number 45 in the example indicates the approximate number of
+ objects that you expect to store in the registry. Internally the
+ registry uses hash tables with collision chaining, so there is no
+ absolute upper limit on the number of objects that the registry can
+ contain, but if performance or memory usage are important, then you
+ should choose a number accordingly. The registry can be resized later.</p>
+ <p>You can open as many registries as you like (if memory permits).</p>
+ <p>Objects are stored and retrieved through set and get functions. In
+ the following examples you see how to store integers, floats, strings
+ and arbitrary binary objects:</p>
+ <code type="none"><![CDATA[
+struct bonk *b = malloc(sizeof(*b));
+char *name = malloc(7);
+
+ei_reg_setival(reg,"age",29);
+ei_reg_setfval(reg,"height",1.85);
+
+strcpy(name,"Martin");
+ei_reg_setsval(reg,"name",name);
+
+b->l = 42;
+b->m = 12;
+ei_reg_setpval(reg,"jox",b,sizeof(*b)); ]]></code>
+ <p>If you attempt to store an object in the registry and there is an
+ existing object with the same key, the new value will replace the old
+ one. This is done regardless of whether the new object and the old one
+ have the same type, so you can, for example, replace a string with an
+ integer. If the existing value is a string or binary, it will be freed
+ before the new value is assigned.</p>
+ <p>Stored values are retrieved from the registry as follows:</p>
+ <code type="none"><![CDATA[
+long i;
+double f;
+char *s;
+struct bonk *b;
+int size;
+
+i = ei_reg_getival(reg,"age");
+f = ei_reg_getfval(reg,"height");
+s = ei_reg_getsval(reg,"name");
+b = ei_reg_getpval(reg,"jox",&size); ]]></code>
+ <p>In all of the above examples, the object must exist and it must be of
+ the right type for the specified operation. If you do not know the
+ type of a given object, you can ask:</p>
+ <code type="none"><![CDATA[
+struct ei_reg_stat buf;
+
+ei_reg_stat(reg,"name",&buf); ]]></code>
+ <p>Buf will be initialized to contain object attributes.</p>
+ <p>Objects can be removed from the registry:</p>
+ <code type="none"><![CDATA[
+ei_reg_delete(reg,"name"); ]]></code>
+ <p>When you are finished with a registry, close it to remove all the
+ objects and free the memory back to the system:</p>
+ <code type="none"><![CDATA[
+ei_reg_close(reg); ]]></code>
+
+ <section>
+ <title>Backing Up the Registry to Mnesia</title>
+ <p>The contents of a registry can be backed up to Mnesia on a "nearby"
+ Erlang node. You need to provide an open connection to the Erlang node
+ (see <c><![CDATA[erl_connect()]]></c>). Also, Mnesia 3.0 or later must be running
+ on the Erlang node before the backup is initiated:</p>
+ <code type="none"><![CDATA[
+ei_reg_dump(fd, reg, "mtab", dumpflags); ]]></code>
+ <p>The example above will backup the contents of the registry to the
+ specified Mnesia table <c><![CDATA["mtab"]]></c>. Once a registry has been backed
+ up to Mnesia in this manner, additional backups will only affect
+ objects that have been modified since the most recent backup, i.e.
+ objects that have been created, changed or deleted. The backup
+ operation is done as a single atomic transaction, so that the entire
+ backup will be performed or none of it will.</p>
+ <p>In the same manner, a registry can be restored from a Mnesia table:</p>
+ <code type="none"><![CDATA[
+ei_reg_restore(fd, reg, "mtab"); ]]></code>
+ <p>This will read the entire contents of <c><![CDATA["mtab"]]></c> into the specified
+ registry. After the restore, all of the objects in the registry will
+ be marked as unmodified, so a subsequent backup will only affect
+ objects that you have modified since the restore.</p>
+ <p>Note that if you restore to a non-empty registry, objects in the
+ table will overwrite objects in the registry with the same keys. Also,
+ the <em>entire</em> contents of the registry is marked as unmodified
+ after the restore, including any modified objects that were not
+ overwritten by the restore operation. This may not be your intention.</p>
+ </section>
+
+ <section>
+ <title>Storing Strings and Binaries</title>
+ <p>When string or binary objects are stored in the registry it is
+ important that a number of simple guidelines are followed. </p>
+ <p>Most importantly, the object must have been created with a single call
+ to <c><![CDATA[malloc()]]></c> (or similar), so that it can later be removed by a
+ single call to <c><![CDATA[free()]]></c>. Objects will be freed by the registry
+ when it is closed, or when you assign a new value to an object that
+ previously contained a string or binary.</p>
+ <p>You should also be aware that if you store binary objects that are
+ context-dependent (e.g. containing pointers or open file descriptors),
+ they will lose their meaning if they are backed up to a Mnesia table
+ and subsequently restored in a different context.</p>
+ <p>When you retrieve a stored string or binary value from the registry,
+ the registry maintains a pointer to the object and you are passed a
+ copy of that pointer. You should never free an object retrieved in
+ this manner because when the registry later attempts to free it, a
+ runtime error will occur that will likely cause the C-node to crash.</p>
+ <p>You are free to modify the contents of an object retrieved this way.
+ However when you do so, the registry will not be aware of the changes
+ you make, possibly causing it to be missed the next time you make a
+ Mnesia backup of the registry contents. This can be avoided if you
+ mark the object as dirty after any such changes with
+ <c><![CDATA[ei_reg_markdirty()]]></c>, or pass appropriate flags to
+ <c><![CDATA[ei_reg_dump()]]></c>.</p>
+ </section>
+ </section>
+</chapter>
+
diff --git a/lib/erl_interface/doc/src/erl_malloc.xml b/lib/erl_interface/doc/src/erl_malloc.xml
new file mode 100644
index 0000000000..8c8750d62a
--- /dev/null
+++ b/lib/erl_interface/doc/src/erl_malloc.xml
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE cref SYSTEM "cref.dtd">
+
+<cref>
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>erl_malloc</title>
+ <prepared>Torbj&ouml;rn T&ouml;rnkvist</prepared>
+ <responsible>Torbj&ouml;rn T&ouml;rnkvist</responsible>
+ <docno></docno>
+ <approved>Bjarne D&auml;cker</approved>
+ <checked>Torbj&ouml;rn T&ouml;rnkvist</checked>
+ <date>980703</date>
+ <rev>A</rev>
+ <file>erl_malloc.sgml</file>
+ </header>
+ <lib>erl_malloc</lib>
+ <libsummary>Memory Allocation Functions</libsummary>
+ <description>
+ <p>This module provides functions for allocating and deallocating
+ memory.</p>
+ </description>
+ <funcs>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_alloc_eterm(etype)</nametext></name>
+ <fsummary>Allocates an ETERM structure</fsummary>
+ <type>
+ <v>unsigned char etype;</v>
+ </type>
+ <desc>
+ <p>This function allocates an <c><![CDATA[(ETERM)]]></c> structure.
+ Specify <c><![CDATA[etype]]></c> as one of the following constants:</p>
+ <list type="bulleted">
+ <item>
+ <p>ERL_INTEGER</p>
+ </item>
+ <item>
+ <p>ERL_U_INTEGER <c><![CDATA[/* unsigned integer */]]></c></p>
+ </item>
+ <item>
+ <p>ERL_ATOM</p>
+ </item>
+ <item>
+ <p>ERL_PID <c><![CDATA[/* Erlang process identifier */]]></c></p>
+ </item>
+ <item>
+ <p>ERL_PORT</p>
+ </item>
+ <item>
+ <p>ERL_REF <c><![CDATA[/* Erlang reference */]]></c></p>
+ </item>
+ <item>
+ <p>ERL_LIST</p>
+ </item>
+ <item>
+ <p>ERL_EMPTY_LIST</p>
+ </item>
+ <item>
+ <p>ERL_TUPLE</p>
+ </item>
+ <item>
+ <p>ERL_BINARY</p>
+ </item>
+ <item>
+ <p>ERL_FLOAT</p>
+ </item>
+ <item>
+ <p>ERL_VARIABLE</p>
+ </item>
+ <item>
+ <p>ERL_SMALL_BIG <c><![CDATA[/* bignum */]]></c></p>
+ </item>
+ <item>
+ <p>ERL_U_SMALL_BIG <c><![CDATA[/* bignum */]]></c></p>
+ </item>
+ </list>
+ <p><c><![CDATA[ERL_SMALL_BIG]]></c> and <c><![CDATA[ERL_U_SMALL_BIG]]></c> are for
+ creating Erlang <c><![CDATA[bignums]]></c>, which can contain integers of
+ arbitrary size. The size of an integer in Erlang is machine
+ dependent, but in general any integer larger than 2^28
+ requires a bignum.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>void</ret><nametext>erl_eterm_release(void)</nametext></name>
+ <fsummary>Clears the ETERM freelist</fsummary>
+ <desc>
+ <p>Clears the
+ freelist, where blocks are placed when they are
+ released by <c><![CDATA[erl_free_term()]]></c> and
+ <c><![CDATA[erl_free_compound()]]></c>. </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>void</ret><nametext>erl_eterm_statistics(allocated, freed)</nametext></name>
+ <fsummary>Reports term allocation statistics</fsummary>
+ <type>
+ <v>long *allocated;</v>
+ <v>long *freed;</v>
+ </type>
+ <desc>
+ <p><c><![CDATA[allocated]]></c> and <c><![CDATA[freed]]></c> are initialized to
+ contain information about the fix-allocator used to allocate
+ ETERM components. <c><![CDATA[allocated]]></c> is the number of blocks
+ currently allocated to ETERM objects. <c><![CDATA[freed]]></c> is the
+ length of the freelist, where blocks are placed when they are
+ released by <c><![CDATA[erl_free_term()]]></c> and
+ <c><![CDATA[erl_free_compound()]]></c>. </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>void</ret><nametext>erl_free_array(array, size)</nametext></name>
+ <fsummary>Frees an array of ETERM structures</fsummary>
+ <type>
+ <v>ETERM **array;</v>
+ <v>int size;</v>
+ </type>
+ <desc>
+ <p>This function frees an array of Erlang terms.</p>
+ <p><c><![CDATA[array]]></c> is an array of ETERM* objects.
+ </p>
+ <p><c><![CDATA[size]]></c> is the number of terms in the array.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>void</ret><nametext>erl_free_term(t)</nametext></name>
+ <fsummary>Frees an ETERM structure</fsummary>
+ <type>
+ <v>ETERM *t;</v>
+ </type>
+ <desc>
+ <p>Use this function to free an Erlang term.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>void</ret><nametext>erl_free_compound(t)</nametext></name>
+ <fsummary>Frees an array of ETERM structures</fsummary>
+ <type>
+ <v>ETERM *t;</v>
+ </type>
+ <desc>
+ <p>Normally it is the programmer's responsibility to free each
+ Erlang term that has been returned from any of the
+ <c><![CDATA[erl_interface]]></c> functions. However since many of the
+ functions that build new Erlang terms in fact share objects
+ with other existing terms, it may be difficult for the
+ programmer to maintain pointers to all such terms in order to
+ free them individually.
+ </p>
+ <p><c><![CDATA[erl_free_compound()]]></c> will recursively free all of the
+ sub-terms associated with a given Erlang term, regardless of
+ whether we are still holding pointers to the sub-terms.
+ </p>
+ <p>There is an example in the User Manual under "Building
+ Terms and Patterns"
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>void</ret><nametext>erl_malloc(size)</nametext></name>
+ <fsummary>Allocates some memory</fsummary>
+ <type>
+ <v>long size;</v>
+ </type>
+ <desc>
+ <p>This function calls the standard
+ <c><![CDATA[malloc()]]></c> function. </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>void</ret><nametext>erl_free(ptr)</nametext></name>
+ <fsummary>Frees some memory</fsummary>
+ <type>
+ <v>void *ptr;</v>
+ </type>
+ <desc>
+ <p>This function calls the standard
+ <c><![CDATA[free()]]></c> function. </p>
+ </desc>
+ </func>
+ </funcs>
+</cref>
+
diff --git a/lib/erl_interface/doc/src/erl_marshal.xml b/lib/erl_interface/doc/src/erl_marshal.xml
new file mode 100644
index 0000000000..a7eaf78f35
--- /dev/null
+++ b/lib/erl_interface/doc/src/erl_marshal.xml
@@ -0,0 +1,272 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE cref SYSTEM "cref.dtd">
+
+<cref>
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>erl_marshal</title>
+ <prepared>Torbj&ouml;rn T&ouml;rnkvist</prepared>
+ <responsible>Torbj&ouml;rn T&ouml;rnkvist</responsible>
+ <docno></docno>
+ <approved>Bjarne D&auml;cker</approved>
+ <checked>Torbj&ouml;rn T&ouml;rnkvist</checked>
+ <date>980703</date>
+ <rev>A</rev>
+ <file>erl_marshal.sgml</file>
+ </header>
+ <lib>erl_marshal</lib>
+ <libsummary>Encoding and Decoding of Erlang terms</libsummary>
+ <description>
+ <p>This module contains functions for encoding Erlang terms into
+ a sequence of bytes, and for decoding Erlang terms from a
+ sequence of bytes.</p>
+ </description>
+ <funcs>
+ <func>
+ <name><ret>int</ret><nametext>erl_compare_ext(bufp1, bufp2)</nametext></name>
+ <fsummary>Compares encoded byte sequences</fsummary>
+ <type>
+ <v>unsigned char *bufp1,*bufp2;</v>
+ </type>
+ <desc>
+ <p>This function compares two encoded terms.
+ </p>
+ <p><c><![CDATA[bufp1]]></c> is a buffer containing an encoded Erlang
+ term term1.
+ </p>
+ <p><c><![CDATA[bufp2]]></c> is a buffer containing an encoded Erlang
+ term term2.
+ </p>
+ <p>The function returns 0 if the terms are equal, -1 if term1
+ is less than term2, or 1 if term2 is less than term1.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>ETERM *</ret><nametext>erl_decode(bufp)</nametext></name>
+ <name><ret>ETERM *</ret><nametext>erl_decode_buf(bufpp)</nametext></name>
+ <fsummary>Converts a term from Erlang external format</fsummary>
+ <type>
+ <v>unsigned char *bufp;</v>
+ <v>unsigned char **bufpp;</v>
+ </type>
+ <desc>
+ <p><c><![CDATA[erl_decode()]]></c> and <c><![CDATA[erl_decode_buf()]]></c> decode
+ the contents of a buffer and return the corresponding
+ Erlang term. <c><![CDATA[erl_decode_buf()]]></c> provides a simple
+ mechanism for dealing with several encoded terms stored
+ consecutively in the buffer.</p>
+ <p><c><![CDATA[bufp]]></c> is a pointer to a buffer containing one or
+ more encoded Erlang terms.
+ </p>
+ <p><c><![CDATA[bufpp]]></c> is the address of a buffer pointer. The buffer
+ contains one or more consecutively encoded Erlang terms.
+ Following a successful call to <c><![CDATA[erl_decode_buf()]]></c>,
+ <c><![CDATA[bufpp]]></c> will be updated so that it points to the next
+ encoded term.
+ </p>
+ <p><c><![CDATA[erl_decode()]]></c> returns an Erlang term
+ corresponding to the contents of <c><![CDATA[bufp]]></c> on success, or
+ NULL on failure. <c><![CDATA[erl_decode_buf()]]></c> returns an Erlang
+ term corresponding to the first of the consecutive terms in
+ <c><![CDATA[bufpp]]></c> and moves <c><![CDATA[bufpp]]></c> forward to point to the
+ next term in the buffer. On failure, each of the functions
+ returns NULL.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_encode(term, bufp)</nametext></name>
+ <name><ret>int</ret><nametext>erl_encode_buf(term, bufpp)</nametext></name>
+ <fsummary>Converts a term into Erlang external format</fsummary>
+ <type>
+ <v>ETERM *term;</v>
+ <v>unsigned char *bufp;</v>
+ <v>unsigned char **bufpp;</v>
+ </type>
+ <desc>
+ <p><c><![CDATA[erl_encode()]]></c> and <c><![CDATA[erl_encode_buf()]]></c> encode
+ Erlang terms into external format for storage or transmission.
+ <c><![CDATA[erl_encode_buf()]]></c> provides a simple mechanism for
+ encoding several terms consecutively in the same
+ buffer.
+ </p>
+ <p><c>term</c> is an Erlang term to be encoded.
+ </p>
+ <p><c>bufp</c> is a pointer to a buffer containing one or
+ more encoded Erlang terms.
+ </p>
+ <p><c>bufpp</c> is a pointer to a pointer to a buffer
+ containing one or more consecutively encoded Erlang terms.
+ Following a successful call to <c><![CDATA[erl_encode_buf()]]></c>,
+ <c>bufpp</c> will be updated so that it points to the
+ position for the next encoded term.
+ </p>
+ <p>
+ These functions returns the number of bytes written to buffer
+ if successful, otherwise returns 0.
+ </p>
+ <p>Note that no bounds checking is done on the buffer. It is
+ the caller's responsibility to make sure that the buffer is
+ large enough to hold the encoded terms. You can either use a
+ static buffer that is large enough to hold the terms you
+ expect to need in your program, or use <c><![CDATA[erl_term_len()]]></c>
+ to determine the exact requirements for a given term.
+ </p>
+ <p>The following can help you estimate the buffer
+ requirements for a term. Note that this information is
+ implementation specific, and may change in future versions.
+ If you are unsure, use <c><![CDATA[erl_term_len()]]></c>.
+ </p>
+ <p>Erlang terms are encoded with a 1 byte tag that
+ identifies the type of object, a 2- or 4-byte length field,
+ and then the data itself. Specifically:
+ </p>
+ <taglist>
+ <tag><c><![CDATA[Tuples]]></c></tag>
+ <item>need 5 bytes, plus the space for each element.</item>
+ <tag><c><![CDATA[Lists]]></c></tag>
+ <item>need 5 bytes, plus the space for each element, and 1
+ additional byte for the empty list at the end.</item>
+ <tag><c><![CDATA[Strings and atoms]]></c></tag>
+ <item>need 3 bytes, plus 1 byte for each character (the
+ terminating 0 is not encoded). Really long strings (more
+ than 64k characters) are encoded as lists. Atoms cannot
+ contain more than 256 characters.</item>
+ <tag><c><![CDATA[Integers]]></c></tag>
+ <item>need 5 bytes.</item>
+ <tag><c><![CDATA[Characters]]></c></tag>
+ <item>(integers &lt; 256) need 2 bytes.</item>
+ <tag><c><![CDATA[Floating point numbers]]></c></tag>
+ <item>need 32 bytes.</item>
+ <tag><c><![CDATA[Pids]]></c></tag>
+ <item>need 10 bytes, plus the space for the node name, which
+ is an atom.</item>
+ <tag><c><![CDATA[Ports and Refs]]></c></tag>
+ <item>need 6 bytes, plus the space for the node name, which
+ is an atom.</item>
+ </taglist>
+ <p>The total space required will be the result calculated
+ from the information above, plus 1 additional byte for a
+ version identifier.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_ext_size(bufp)</nametext></name>
+ <fsummary>Counts elements in encoded term</fsummary>
+ <type>
+ <v>unsigned char *bufp;</v>
+ </type>
+ <desc>
+ <p>This function returns the number of elements in an
+ encoded term.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>unsigned char</ret><nametext>erl_ext_type(bufp)</nametext></name>
+ <fsummary>Determines type of an encoded byte sequence</fsummary>
+ <type>
+ <v>unsigned char *bufp;</v>
+ </type>
+ <desc>
+ <p>This function identifies and returns the type of Erlang term encoded
+ in a buffer. It will skip a trailing <em>magic</em> identifier.
+ Returns <c><![CDATA[0]]></c> if the type can't be determined or one of</p>
+ <list type="bulleted">
+ <item>
+ <p>ERL_INTEGER</p>
+ </item>
+ <item>
+ <p>ERL_ATOM</p>
+ </item>
+ <item>
+ <p>ERL_PID <c><![CDATA[/* Erlang process identifier */]]></c></p>
+ </item>
+ <item>
+ <p>ERL_PORT</p>
+ </item>
+ <item>
+ <p>ERL_REF <c><![CDATA[/* Erlang reference */]]></c></p>
+ </item>
+ <item>
+ <p>ERL_EMPTY_LIST</p>
+ </item>
+ <item>
+ <p>ERL_LIST</p>
+ </item>
+ <item>
+ <p>ERL_TUPLE</p>
+ </item>
+ <item>
+ <p>ERL_FLOAT</p>
+ </item>
+ <item>
+ <p>ERL_BINARY</p>
+ </item>
+ <item>
+ <p>ERL_FUNCTION</p>
+ </item>
+ </list>
+ </desc>
+ </func>
+ <func>
+ <name><ret>unsigned char *</ret><nametext>erl_peek_ext(bufp, pos)</nametext></name>
+ <fsummary>Steps over encoded term</fsummary>
+ <type>
+ <v>unsigned char *bufp;</v>
+ <v>int pos;</v>
+ </type>
+ <desc>
+ <p>This function is used for stepping over one or more
+ encoded terms in a buffer, in order to directly access a
+ later term.
+ </p>
+ <p><c><![CDATA[bufp]]></c> is a pointer to a buffer containing one or
+ more encoded Erlang terms.
+ </p>
+ <p><c><![CDATA[pos]]></c> indicates how many terms to step over in the
+ buffer.
+ </p>
+ <p>The function returns a pointer to a sub-term that can be
+ used in a subsequent call to <c><![CDATA[erl_decode()]]></c> in order to retrieve
+ the term at that position. If there is no term, or <c><![CDATA[pos]]></c>
+ would exceed the size of the terms in the buffer, NULL is returned.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>erl_term_len(t)</nametext></name>
+ <fsummary>Determines encoded size of term</fsummary>
+ <type>
+ <v>ETERM *t;</v>
+ </type>
+ <desc>
+ <p>This function determines the buffer space that would be
+ needed by <c><![CDATA[t]]></c> if it were encoded into Erlang external
+ format by <c><![CDATA[erl_encode()]]></c>.
+ </p>
+ <p>The size in bytes is returned.
+ </p>
+ </desc>
+ </func>
+ </funcs>
+</cref>
+
diff --git a/lib/erl_interface/doc/src/fascicules.xml b/lib/erl_interface/doc/src/fascicules.xml
new file mode 100644
index 0000000000..3d6219a2bd
--- /dev/null
+++ b/lib/erl_interface/doc/src/fascicules.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE fascicules SYSTEM "fascicules.dtd">
+
+<fascicules>
+ <fascicule file="part_ei" href="part_ei_frame.html" entry="no">
+ EI User's Guide
+ </fascicule>
+ <fascicule file="ref_man_ei" href="ref_man_ei_frame.html" entry="yes">
+ EI Library Reference
+ </fascicule>
+ <fascicule file="ref_man_erl_interface" href="ref_man_erl_interface_frame.html" entry="no">
+ Erl_interface Library Reference
+ </fascicule>
+ <fascicule file="ref_man" href="ref_man_frame.html" entry="no">
+ Command Reference
+ </fascicule>
+ <fascicule file="part_notes" href="part_notes_frame.html" entry="no">
+ Release Notes
+ </fascicule>
+ <fascicule file="" href="../../../../doc/print.html" entry="no">
+ Off-Print
+ </fascicule>
+</fascicules>
+
diff --git a/lib/erl_interface/doc/src/make.dep b/lib/erl_interface/doc/src/make.dep
new file mode 100644
index 0000000000..3f43cf64fe
--- /dev/null
+++ b/lib/erl_interface/doc/src/make.dep
@@ -0,0 +1,24 @@
+# ----------------------------------------------------
+# >>>> Do not edit this file <<<<
+# This file was automaticly generated by
+# /home/otp/bin//docdepend
+# ----------------------------------------------------
+
+
+# ----------------------------------------------------
+# TeX files that the DVI file depend on
+# ----------------------------------------------------
+
+book.dvi: book.tex ei.tex ei_connect.tex ei_users_guide.tex \
+ erl_call.tex erl_connect.tex erl_error.tex \
+ erl_eterm.tex erl_format.tex erl_global.tex \
+ erl_malloc.tex erl_marshal.tex part_ei.tex \
+ ref_man.tex ref_man_ei.tex ref_man_erl_interface.tex \
+ registry.tex
+
+# ----------------------------------------------------
+# Source inlined when transforming from source to LaTeX
+# ----------------------------------------------------
+
+book.tex: ref_man.xml ref_man_ei.xml ref_man_erl_interface.xml
+
diff --git a/lib/erl_interface/doc/src/note.gif b/lib/erl_interface/doc/src/note.gif
new file mode 100644
index 0000000000..6fffe30419
--- /dev/null
+++ b/lib/erl_interface/doc/src/note.gif
Binary files differ
diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml
new file mode 100644
index 0000000000..f2519fda0b
--- /dev/null
+++ b/lib/erl_interface/doc/src/notes.xml
@@ -0,0 +1,535 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Erl_interface Release Notes</title>
+ <prepared>otp_appnotes</prepared>
+ <docno>nil</docno>
+ <date>nil</date>
+ <rev>nil</rev>
+ <file>notes.xml</file>
+ </header>
+ <p>This document describes the changes made to the Erl_interface application.</p>
+
+<section><title>Erl_Interface 3.6.4</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The documentation is now built with open source tools
+ (xsltproc and fop) that exists on most platforms. One
+ visible change is that the frames are removed.</p>
+ <p>
+ Own Id: OTP-8201</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.6.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The manual states that erl_receive() return the reason in
+ the <c>ErlMessage</c> struct. This was not the case and
+ the function is now corrected.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-4969</p>
+ </item>
+ <item>
+ <p>
+ In <c>send_exit.c</c> an errorneous size of memory
+ allocation could occur when reallocating a buffer.</p>
+ <p>
+ In <c>ei_decode_trace.c</c> the index could be updated
+ when the decoding failed.</p>
+ <p>
+ In <c>ei_printterm.c</c> the index could be updated when
+ the decoding failed in lists and tuples.</p>
+ <p>
+ In <c>ei_decode_term.c</c> when decoding a double
+ (ERL_FLOAT_EXT) no check was done to ensure that the last
+ of the 31 bytes was null terminated.</p>
+ <p>
+ In <c>ei_decode_term.c</c> when decoding references, only
+ the first 3 bytes are read, but the index did not
+ increment by the total size.</p>
+ <p>
+ In <c>ei_decode_fun.c</c> no check of correct buffer
+ allocation or data length was done.</p>
+ <p>
+ In <c>ei_decode_string.c</c> the integer list string case
+ did not decode the NIL tail correctly.</p>
+ <p>
+ These errors has now been fixed. (Thanks to Romain
+ Lenglet, Paul Mineiro and Paul Guyot).</p>
+ <p>
+ Own Id: OTP-6117</p>
+ </item>
+ <item>
+ <p>
+ <c>ei_decode_big</c> could be decoded with a garbage
+ byte.</p>
+ <p>
+ <c>ei_encode_big</c> and <c>ei_x_encode_big</c> is now
+ available.</p>
+ <p>
+ Own Id: OTP-7554</p>
+ </item>
+ <item>
+ <p>
+ The function <c>erl_init_resolve()</c> did not conform to
+ C99 standard which caused a build error on some
+ platforms. This has now been fixed.</p>
+ <p>
+ Own Id: OTP-8093</p>
+ </item>
+ <item>
+ <p>
+ <c>Makefile.in</c> has been updated to use the LDFLAGS
+ environment variable (if set). (Thanks to Davide
+ Pesavento.)</p>
+ <p>
+ Own Id: OTP-8157</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Added support for 64-bit integers in encoding/decoding.</p>
+ <p>
+ Added support for better printouts of binaries.</p>
+ <p>
+ Own Id: OTP-6091</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.6.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A problem with <c>gethostbyname</c> in <c>erl_start.c</c>
+ could cause a buffer overflow. This has now been fixed.</p>
+ <p>
+ Clean up of code and removed compiler warnings.</p>
+ <p>
+ Own Id: OTP-7978</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.6.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>A faulty validation in <c>ei_reg_getpval</c> caused it
+ to never return the key-value. This has now been fixed.
+ (Thanks to Matt Stancliff)</p>
+ <p>
+ Own Id: OTP-7960</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Minor update to the <c>configure</c> script.</p>
+ <p>
+ Own Id: OTP-7959</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.6.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Minor update to the <c>configure</c> script.</p>
+ <p>
+ Own Id: OTP-7959</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.6</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Nodes belonging to different independent clusters can now
+ co-exist on the same host with the help of a new
+ environment variable setting ERL_EPMD_PORT.</p>
+ <p>
+ Own Id: OTP-7826</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.5.9</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A type-casting bug in ei_skip_term and ei_printterm on
+ 64bit platforms rendering undefined results is now
+ corrected.</p>
+ <p>
+ Own Id: OTP-7577</p>
+ </item>
+ <item>
+ <p>
+ A bug in the hostent copying code of erl_interface on
+ MacOS X/Darwin is now corrected.</p>
+ <p>
+ Own Id: OTP-7593</p>
+ </item>
+ <item>
+ <p>A problem with building <c>erl_interface</c> on
+ FreeBSD has been fixed (Thanks to Akira Kitada).</p>
+ <p>
+ Own Id: OTP-7611</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.5.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed bug in erl_interface when decoding broken data</p>
+ <p>
+ Own Id: OTP-7448</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+
+<section><title>Erl_Interface 3.5.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ An erroneous freeing of memory could occur when using
+ <c>ei_x_format_wo_ver</c> in erl_interface, resulting in
+ a segmentation fault.</p>
+ <p>
+ Own Id: OTP-6795</p>
+ </item>
+ <item>
+ <p>
+ A faulty compare in <c>erl_marshal</c> has now been
+ fixed. (Thanks to Simon Cornish and Paul Mineiro)</p>
+ <p>
+ Own Id: OTP-7368</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.5.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Minor documentation fixes.</p>
+ <p>
+ Own Id: OTP-7183 Aux Id: OTP-7118 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.5.5.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The symbol __erl_errno was undefined in the single thread
+ version of the ei library, but is now defined.</p>
+ <p>
+ Own Id: OTP-6887</p>
+ </item>
+ <item>
+ <p>
+ Corrected FreeBSD build error.</p>
+ <p>
+ Own Id: OTP-7093</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+ <section>
+ <title>Erl_Interface 3.5.5.3</title>
+
+ <section>
+ <title>Improvements and New Features</title>
+ <list type="bulleted">
+ <item>
+ <p>Calls to alloca in erl_marshal.c have been removed. A
+ static buffer is now used instead to store node names
+ temporarily.</p>
+ <p>Own Id: OTP-6331 Aux Id: seq10468 </p>
+ </item>
+ <item>
+ <p>ei_print_term interprets a list of integers with values
+ from 0 to 255 as a string. If the original list contains
+ the integer 0, this is considered terminator of the
+ string. This is incorrect. The function has now been
+ modified to not look for '\\0' in a string, but always
+ print all characters.</p>
+ <p>Own Id: OTP-6339 Aux Id: seq10492 </p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_Interface 3.5.5.2</title>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>The combination of xeon processors with 64bit x86
+ extensions and a 32bit linux could cause ei_decode_long
+ and ei_decode_longlong to fail for the value LONG_MIN and
+ LONGLONG_MIN. The conversion is now made more portable.</p>
+ <p>Own Id: OTP-6216</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_Interface 3.5.5.1</title>
+
+ <section>
+ <title>Improvements and New Features</title>
+ <list type="bulleted">
+ <item>
+ <p>Portability enhancements.</p>
+ <p>Own Id: OTP-6132</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_Interface 3.5.5</title>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Different (and old) <c><![CDATA[config.guess]]></c> files in the
+ <c><![CDATA[erts]]></c> and <c><![CDATA[erl_interface]]></c> applications would
+ cause build problems on the new Intel-based iMacs.
+ (Thanks to Sebastion Strollo.)</p>
+ <p>Own Id: OTP-5967</p>
+ </item>
+ <item>
+ <p>pthread header and library mismatch on linux systems (at
+ least some SuSE and Debian) with both NPTL and
+ Linuxthreads libraries installed.</p>
+ <p>Own Id: OTP-5981</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Improvements and New Features</title>
+ <list type="bulleted">
+ <item>
+ <p>Support for a C node to connect to an Erlang node on a
+ standalone host has been added.</p>
+ <p>Own Id: OTP-5883 Aux Id: seq10170 </p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_interface 3.5.2</title>
+
+ <section>
+ <title>Improvements and New Features</title>
+ <list type="bulleted">
+ <item>
+ <p>A configuration test error caused erl_interface to be
+ built without support for threads. This has been
+ corrected.</p>
+ <p>Own Id: OTP-5456</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_interface 3.5.1</title>
+
+ <section>
+ <title>Improvements and New Features</title>
+ <list type="bulleted">
+ <item>
+ <p>Changes and improvements have been made to the build and
+ test environment to solve problems with failing
+ erl_interface test cases.</p>
+ <p>Own Id: OTP-5295 Aux Id: OTP-5387 </p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_interface 3.5</title>
+
+ <section>
+ <title>Improvements and New Features</title>
+ <list type="bulleted">
+ <item>
+ <p>Process identifiers and port identifiers have been
+ made more unique. Previously 18 bits were used as id in
+ the internal representation of process and port
+ identifiers. Now 28 bits are used. </p>
+ <p>The maximum
+ limit on the number of concurrently existing processes
+ due to the representation of pids has been increased to
+ 268435456 processes. The same is true for ports. This
+ limit will at least on a 32-bit architecture be
+ impossible to reach due to memory shortage. </p>
+ <p><em>NOTE:</em> By default, the <c><![CDATA[ERTS]]></c>, and the
+ <c><![CDATA[erl_interface]]></c>, <c><![CDATA[ei]]></c>, and <c><![CDATA[jinterface]]></c>
+ libraries are now only guaranteed to be compatible with
+ other Erlang/OTP components from the same release. It is
+ possible to set each component in compatibility mode of
+ an earlier release, though. See the documentation for
+ respective component on how to set it in compatibility
+ mode. </p>
+ <p>*** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>Own Id: OTP-4968 Aux Id: OTP-4196 </p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_interface 3.4.5</title>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Corrections for mistakes done for patch erl_605/OTP-4874.</p>
+ <p>Own Id: OTP-4995 Aux Id: OTP-4874 </p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_interface 3.4.4</title>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>A small optimization in ei_rpc*() was added and a bug in
+ ei_decode_longlong() was corrected.</p>
+ <p>Own Id: OTP-4784</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_interface 3.4.2</title>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Strings longer than 65535 bytes were encoded wrong in
+ ei/erl_interface.</p>
+ <p>Own Id: OTP-4865 Aux Id: EABln07451 </p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_interface 3.4.1</title>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>erl_call -a parsed erlang terms incorrectly due to a bug
+ in ei_format, which is now corrected.</p>
+ <p>Own Id: OTP-4777 Aux Id: seq8099 </p>
+ </item>
+ </list>
+ </section>
+ </section>
+</chapter>
+
diff --git a/lib/erl_interface/doc/src/notes_history.xml b/lib/erl_interface/doc/src/notes_history.xml
new file mode 100644
index 0000000000..f484f3c04e
--- /dev/null
+++ b/lib/erl_interface/doc/src/notes_history.xml
@@ -0,0 +1,367 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2006</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Erl_Interface Release Notes History</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+
+ <section>
+ <title>Erl_Interface 3.4</title>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p><c><![CDATA[erl_print_term()]]></c> and <c><![CDATA[erl_copy_term()]]></c> could not
+ previously handle uints. This bug has now been fixed.</p>
+ <p>Own Id: OTP-4061 Aux Id: seq7079</p>
+ </item>
+ <item>
+ <p><c><![CDATA[ei_x_format()]]></c> was not working correctly for floating
+ point arguments on some platforms. This is now corrected.</p>
+ <p>Own Id: OTP-4379</p>
+ </item>
+ <item>
+ <p><c><![CDATA[erl_compare_ext()]]></c> did not compare the node parts of
+ pids, ports, and references. This has now been fixed.
+ Comparison between two pids, ports, or references does now
+ conform to the Erlang specification.</p>
+ <p>Own Id: OTP-4512 Aux Id: OTP-4511</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Improvements and New Features</title>
+ <list type="bulleted">
+ <item>
+ <p>Erl_Interface and EI now supports 64 bit architectures.</p>
+ <p>Own Id: OTP-4772</p>
+ </item>
+ <item>
+ <p>There are new functions that support the GCC and Visual
+ C++ 64 bit extended integer types.</p>
+ <code type="none"><![CDATA[
+int ei_decode_longlong(const char *buf, int *index, EI_LONGLONG *p);
+int ei_decode_ulonglong(const char *buf, int *index, EI_ULONGLONG *p);
+int ei_encode_longlong(char *buf, int *index, EI_LONGLONG p);
+int ei_encode_ulonglong(char *buf, int *index, EI_ULONGLONG p);
+int ei_x_encode_longlong(ei_x_buff* x, EI_LONGLONG n);
+int ei_x_encode_ulonglong(ei_x_buff* x, EI_ULONGLONG n);
+ ]]></code>
+ <p>Own Id: OTP-4772</p>
+ </item>
+ <item>
+ <p>If you compile the library from source you can use the ei
+ library together with GMP, the GNU multi precision
+ library, to convert integers larger than 64 bits from and
+ to the external format.</p>
+ <code type="none"><![CDATA[
+int ei_decode_bignum(const char *buf, int *index, mpz_t obj);
+int ei_encode_bignum(char *buf, int *index, mpz_t obj);
+int ei_x_encode_bignum(ei_x_buff *x, mpz_t obj);
+ ]]></code>
+ <p>Own Id: OTP-4772</p>
+ </item>
+ <item>
+ <p>Some general code improvements where done like correcting
+ buffer sizes, added more error checking etc.</p>
+ <p>Own Id: OTP-4772</p>
+ </item>
+ <item>
+ <p>In order to conform to the Erlang specification,
+ comparison between two pids was changed in the R9B
+ release. This change did however break a deadlock
+ prevention algorithm used by Mnesia during release
+ upgrade. Therefore, comparison between two pids has been
+ changed back so that R9B nodes are compatible with Erlang
+ nodes running pre-R9 releases.</p>
+ <p>Pre-R9 comparison between two pids which now is used
+ again: If t1 and t2 are both pids, t1 will precede t2 if
+ and only if either</p>
+ <list type="bulleted">
+ <item>the node local id of t1 precedes the node local id
+ of t2, or</item>
+ <item>the node local ids of t1 and t2 are equal, and
+ node(t1) precedes node(t2), or</item>
+ <item>the node local ids of t1 and t2 are equal, and also
+ node(t1) and node(t2) are equal, and node(t1) was
+ created before node(t2).</item>
+ </list>
+ <p>The node local id consist of two integers; serial which
+ is most significant, and number.</p>
+ <p>The Erlang specification states: If t1 and t2 are both
+ refs, both PIDs, or both ports, then t1 precedes t2 if
+ and only if either</p>
+ <list type="bulleted">
+ <item>node(t1) precedes node(t2), or</item>
+ <item>node(t1) equals node(t2) and t1 was created before
+ t2.</item>
+ </list>
+ <p>Note that comparisons between two refs, or two ports will
+ still conform to the Erlang specification.</p>
+ <p>*** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>Own Id: OTP-4715 Aux Id: OTP-4511, OTP-4512</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>ErlInterface 3.3</title>
+
+ <section>
+ <title>Improvements and New Features</title>
+ <list type="bulleted">
+ <item>
+ <p>Erl_Interface has been rewritten extensively. The library
+ <c><![CDATA[ei]]></c> is now documented and supported. The old
+ <c><![CDATA[erl_interface]]></c> is considered obsolete, and provided
+ only for backward compatibility.</p>
+ </item>
+ <item>
+ <p>Erl_Interface is now thread-safe, and multiple C-nodes may
+ run from the same process.</p>
+ </item>
+ <item>
+ <p>New functions are added for connecting and accepting
+ connections from <c><![CDATA[ei]]></c>; these are documented in
+ <c><![CDATA[ei_connect]]></c>.</p>
+ </item>
+ <item>
+ <p>New functions are added for converting to and from Erlang
+ binary format; these are documented in <c><![CDATA[ei]]></c>.</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_Interface 3.2.9</title>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Changed back the return values from <c><![CDATA[erl_send()]]></c> and
+ <c><![CDATA[erl_reg_send()]]></c> to 1 (as they used to be).
+ Incompatible with plain R7, compatible with previous
+ versions.</p>
+ <p>*** INCOMPATIBILITY with R7B ***</p>
+ <p>Own Id: OTP-3772</p>
+ </item>
+ <item>
+ <p>A race-condition bug in the term allocation routines was
+ corrected.</p>
+ <p>Own Id: OTP-3809</p>
+ </item>
+ <item>
+ <p>Erl_Interface could not be linked with pthreads.</p>
+ <p>Own Id: OTP-3810 Aux Id: Seq 5032</p>
+ </item>
+ <item>
+ <p>The TCB of VxWorks processes no longer grows when
+ <c><![CDATA[erl_errno]]></c> is accessed. On Pthreads platforms
+ the use of <c><![CDATA[erl_errno]]></c> no longer crashes programs
+ using multithreading.</p>
+ <p>Own Id: OTP-3820</p>
+ </item>
+ <item>
+ <p>Name clashes between Erlang emulator and Erl_Interface
+ on VxWorks removed.</p>
+ <p>Own Id: OTP-3824</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_Interface 3.2.3</title>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Memory lossage affecting pids, ports and refs fixed.</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_Interface 3.2.2</title>
+
+ <section>
+ <title>Improvements and New Features</title>
+ <list type="bulleted">
+ <item>
+ <p>An error reporting facility <c><![CDATA[erl_errno]]></c> has been
+ introduced.</p>
+ <p>Own Id: OTP-3641</p>
+ </item>
+ <item>
+ <p>ETERMs are now shrunk to a more reasonable size.</p>
+ <p>Own Id: OTP-3648</p>
+ <p></p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_Interface 3.2.1</title>
+
+ <section>
+ <title>Fixed Errors and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Lists containing negative numbers were incorrectly
+ encoded by <c><![CDATA[erl_encode()]]></c>. This has been corrected.</p>
+ <p>Own Id: OTP-3535</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_Interface 3.2</title>
+
+ <section>
+ <title>Improvements and New Features</title>
+ <list type="bulleted">
+ <item>
+ <p>The reference type has been extended from 18 bits to
+ 82 bits. For compatibility with older nodes, an R6 node
+ can send a ref to an older node; if the older node sends
+ it back, it has lost all but its 18 least significant
+ bits, but still compares equal to the original ref.
+ The external format has been extended to represent the new
+ longer refs; that means for example that binaries with
+ refs, produced on an R6 node, cannot be converted to a
+ term on an older node.
+ In <c><![CDATA[erl_interface]]></c>, a function <c><![CDATA[erl_mk_long_ref]]></c>
+ has been added, and macros <c><![CDATA[ERL_REF_NUMBERS]]></c> and
+ <c><![CDATA[ERL_REF_LEN]]></c>.</p>
+ <p>*** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>Own Id: OTP-3140 Aux Id: OTP-3139</p>
+ </item>
+ <item>
+ <p>The function <c><![CDATA[erl_receive_msg]]></c> has the problem that
+ a fixed buffer must be given - a larger message than
+ expected is simply discarded. A function
+ <c><![CDATA[erl_xreceive_msg]]></c> has been introduced, which
+ dynamically resizes the buffer given to it, if needed.</p>
+ <p>Own Id: OTP-3313 Aux Id: OTP-2927</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_Interface 3.1.1</title>
+
+ <section>
+ <title>Improvements and New Features</title>
+ <list type="bulleted">
+ <item>
+ <p><c><![CDATA[#ifdef __cplusplus extern C {]]></c> is added to all the
+ <c><![CDATA[erl*.h]]></c> and <c><![CDATA[ei*.h]]></c> files in order to support
+ use from C++.</p>
+ <p>On Unix the object files are now produced with
+ the <c><![CDATA[-fPIC]]></c> option to make it possible to include
+ them in a shared library.</p>
+ <p>Own Id: OTP-3138 Aux Id: Seq 1722</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>Erl_Interface 3.1</title>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>A buffer overflow in <c><![CDATA[erl_connect()]]></c> was causing
+ C-node crashes on Linux.</p>
+ <p>Own Id: OTP-2743</p>
+ </item>
+ <item>
+ <p>When decoding very long strings (more than 65535
+ characters) the terminating 0 was left out.</p>
+ <p>Own Id: OTP-2744</p>
+ </item>
+ <item>
+ <p><c><![CDATA[erl_accept()]]></c> was not handshaking properly with
+ Erlang, causing incoming connection attempts to fail.</p>
+ <p>Own Id: OTP-2862</p>
+ </item>
+ <item>
+ <p>Very large negative numbers are no longer encoded
+ incorrectly.</p>
+ <p>Own Id: OTP-2897</p>
+ </item>
+ <item>
+ <p>Atoms could sometimes contain an unterminated string.
+ This is fixed.</p>
+ <p>Own Id: OTP-2956</p>
+ </item>
+ <item>
+ <p>Erl_Interface now uses the SENS resolver functions if
+ they are available at runtime. This primarily concerns
+ use on the VxWorks platform.</p>
+ <p>Own Id: OTP-3034 Aux Id: Seq 1559</p>
+ </item>
+ <item>
+ <p>The documentation for <c><![CDATA[erl_connect_init()]]></c> no longer
+ makes erroneous reference to the remote node.</p>
+ <p>Own Id: OTP-3102 Aux Id: Seq 1671</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Improvements and New Features</title>
+ <list type="bulleted">
+ <item>
+ <p>Erl_Interface has been moved out of the Erlang runtime
+ system (ERTS) and is now a separate application. This has
+ implications for all users of Erl_Interface, who will
+ need to make changes to the Makefiles used to build
+ applications based on Erl_Interface. In particular,
+ header and library files are no longer in
+ <c><![CDATA[$(OTPROOT)/usr/]]></c>. The <c><![CDATA[include]]></c> and <c><![CDATA[lib]]></c>
+ directories are now located in the directory
+ <c><![CDATA[$(OTPROOT)/lib/erl_interface-3.1]]></c> (i.e.
+ the directory name is now version specific).</p>
+ <p>Own Id: OTP-3082</p>
+ </item>
+ </list>
+ </section>
+ </section>
+</chapter>
+
diff --git a/lib/erl_interface/doc/src/part.xml b/lib/erl_interface/doc/src/part.xml
new file mode 100644
index 0000000000..e38b9164b8
--- /dev/null
+++ b/lib/erl_interface/doc/src/part.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2002</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>EI User's Guide</title>
+ <prepared>Gordon Beaton</prepared>
+ <docno></docno>
+ <date>1998-11-30</date>
+ <rev>1.2</rev>
+ <file>part.xml</file>
+ </header>
+ <xi:include href="ei_users_guide.xml"/>
+</part>
+
diff --git a/lib/erl_interface/doc/src/part_erl_interface.xml b/lib/erl_interface/doc/src/part_erl_interface.xml
new file mode 100644
index 0000000000..c69cc85c63
--- /dev/null
+++ b/lib/erl_interface/doc/src/part_erl_interface.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Erl_Interface User's Guide</title>
+ <prepared>Gordon Beaton</prepared>
+ <docno></docno>
+ <date>1998-11-30</date>
+ <rev>1.2</rev>
+ <file>part_erl_interface.sgml</file>
+ </header>
+ <xi:include href="erl_interface.xml"/>
+</part>
+
diff --git a/lib/erl_interface/doc/src/part_notes.xml b/lib/erl_interface/doc/src/part_notes.xml
new file mode 100644
index 0000000000..14c1de1d6e
--- /dev/null
+++ b/lib/erl_interface/doc/src/part_notes.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Erl_Interface Release Notes</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+ <description>
+ <p><em>Erl_Interface</em> is a C interface library for communication
+ with Erlang.</p>
+ <p>For information about older versions, see
+ <url href="part_notes_history_frame.html">Release Notes History</url>.</p>
+ </description>
+ <xi:include href="notes.xml"/>
+</part>
+
diff --git a/lib/erl_interface/doc/src/part_notes_history.xml b/lib/erl_interface/doc/src/part_notes_history.xml
new file mode 100644
index 0000000000..612b4a9e1e
--- /dev/null
+++ b/lib/erl_interface/doc/src/part_notes_history.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2006</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Erl_Interface Release Notes History</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+ <description>
+ <p><em>Erl_Interface</em> is a C interface library for communication
+ with Erlang.</p>
+ </description>
+ <xi:include href="notes_history.xml"/>
+</part>
+
diff --git a/lib/erl_interface/doc/src/ref_man.xml b/lib/erl_interface/doc/src/ref_man.xml
new file mode 100644
index 0000000000..9ae4cf27f5
--- /dev/null
+++ b/lib/erl_interface/doc/src/ref_man.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE application SYSTEM "application.dtd">
+
+<application xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>1998</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+ <title>Erl_Interface Command Reference</title>
+ <prepared>Gordon Beaton</prepared>
+ <docno></docno>
+ <date>1998-11.30</date>
+ <rev>1.2</rev>
+ <file>ref_man.xml</file>
+ </header>
+ <description>
+ <p>The <c>ei</c> and <c>erl_interface</c> are <c>C</c> interface libraries for
+ communication with <c>Erlang</c>.</p>
+ <note>
+ <p>By default, the <c>ei</c> and <c>erl_interface</c> libraries are only guaranteed
+ to be compatible with other Erlang/OTP components from the same
+ release as the libraries themself. See the documentation of the
+ <seealso marker="ei#ei_set_compat_rel">ei_set_compat_rel()</seealso> and
+ <seealso marker="erl_eterm#erl_set_compat_rel">erl_set_compat_rel()</seealso>
+ functions on how to communicate with Erlang/OTP components from earlier
+ releases.</p>
+ </note>
+ </description>
+ <xi:include href="ei.xml"/>
+ <xi:include href="ei_connect.xml"/>
+ <xi:include href="registry.xml"/>
+ <xi:include href="erl_connect.xml"/>
+ <xi:include href="erl_error.xml"/>
+ <xi:include href="erl_eterm.xml"/>
+ <xi:include href="erl_format.xml"/>
+ <xi:include href="erl_global.xml"/>
+ <xi:include href="erl_malloc.xml"/>
+ <xi:include href="erl_marshal.xml"/>
+ <xi:include href="erl_call.xml"/>
+</application>
+
diff --git a/lib/erl_interface/doc/src/ref_man_ei.xml b/lib/erl_interface/doc/src/ref_man_ei.xml
new file mode 100644
index 0000000000..ff161f9e7f
--- /dev/null
+++ b/lib/erl_interface/doc/src/ref_man_ei.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE application SYSTEM "application.dtd">
+
+<application xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>2002</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>EI Library Reference</title>
+ <prepared>Gordon Beaton</prepared>
+ <docno></docno>
+ <date>1998-11-30</date>
+ <rev>1.2</rev>
+ <file>ref_man_ei.xml</file>
+ </header>
+ <description>
+ <p>The <c><![CDATA[ei]]></c> library is a <c><![CDATA[C]]></c> interface library for
+ communication with <c><![CDATA[Erlang]]></c>.</p>
+ <note>
+ <p>By default, the <c><![CDATA[ei]]></c> library is only guaranteed
+ to be compatible with other Erlang/OTP components from the same
+ release as the <c><![CDATA[ei]]></c> library itself. See the documentation of the
+ <seealso marker="ei#ei_set_compat_rel">ei_set_compat_rel()</seealso>
+ function on how to communicate with Erlang/OTP components from earlier
+ releases.</p>
+ </note>
+ </description>
+ <xi:include href="ei.xml"/>
+ <xi:include href="ei_connect.xml"/>
+ <xi:include href="registry.xml"/>
+</application>
+
diff --git a/lib/erl_interface/doc/src/ref_man_erl_interface.xml b/lib/erl_interface/doc/src/ref_man_erl_interface.xml
new file mode 100644
index 0000000000..7ffa0cfb23
--- /dev/null
+++ b/lib/erl_interface/doc/src/ref_man_erl_interface.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE application SYSTEM "application.dtd">
+
+<application xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Erl_Interface Library Reference</title>
+ <prepared>Gordon Beaton</prepared>
+ <docno></docno>
+ <date>1998-11-30</date>
+ <rev>1.2</rev>
+ <file>ref_man_erl_interface.xml</file>
+ </header>
+ <description>
+ <p>The <c>erl_interface</c> library is a <c>C</c> interface library
+ for communication with <c>Erlang</c>.</p>
+ <note>
+ <p>By default, the <c>erl_interface</c> library is only guaranteed
+ to be compatible with other Erlang/OTP components from the same
+ release as the <c>erl_interface</c> library. See the documentation
+ of the
+ <seealso marker="erl_eterm#erl_set_compat_rel">erl_set_compat_rel()</seealso>
+ function on how to communicate with Erlang/OTP components from earlier
+ releases.</p>
+ </note>
+ </description>
+ <xi:include href="erl_connect.xml"/>
+ <xi:include href="erl_error.xml"/>
+ <xi:include href="erl_eterm.xml"/>
+ <xi:include href="erl_format.xml"/>
+ <xi:include href="erl_global.xml"/>
+ <xi:include href="erl_malloc.xml"/>
+ <xi:include href="erl_marshal.xml"/>
+</application>
+
diff --git a/lib/erl_interface/doc/src/registry.xml b/lib/erl_interface/doc/src/registry.xml
new file mode 100644
index 0000000000..8aeb378d95
--- /dev/null
+++ b/lib/erl_interface/doc/src/registry.xml
@@ -0,0 +1,611 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE cref SYSTEM "cref.dtd">
+
+<cref>
+ <header>
+ <copyright>
+ <year>1998</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>registry</title>
+ <prepared>Gordon Beaton</prepared>
+ <responsible>Gordon Beaton</responsible>
+ <docno></docno>
+ <approved>Gordon Beaton</approved>
+ <checked>Gordon Beaton</checked>
+ <date>980707</date>
+ <rev>A</rev>
+ <file>registry.sgml</file>
+ </header>
+ <lib>registry</lib>
+ <libsummary>Store and backup key-value pairs</libsummary>
+ <description>
+ <p>This module provides support for storing key-value
+ pairs in a table known as a registry, backing up registries to
+ Mnesia in an atomic manner, and later restoring the contents of a
+ registry from Mnesia.</p>
+ </description>
+ <funcs>
+ <func>
+ <name><ret>ei_reg *</ret><nametext>ei_reg_open(size)</nametext></name>
+ <fsummary>Create and open a registry</fsummary>
+ <type>
+ <v>int size;</v>
+ </type>
+ <desc>
+ <p>Open (create) a registry. The registry will be
+ initially empty. Use <c><![CDATA[ei_reg_close()]]></c> to close the registry
+ later.
+ </p>
+ <p><c><![CDATA[size]]></c> is the approximate number of objects you intend
+ to store in the registry. Since the registry uses a hash table
+ with collision chaining, there is no absolute upper limit on the
+ number of objects that can be stored in it. However for reasons
+ of efficiency, it is a good idea to choose a number that is
+ appropriate for your needs. It is possible to use
+ <c><![CDATA[ei_reg_resize()]]></c> to change the size later. Note that the
+ number you provide will be increased to the nearest larger prime
+ number.
+ </p>
+ <p>On success, an empty registry will be returned. On failure, NULL
+ will be returned.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_resize(reg,newsize)</nametext></name>
+ <fsummary>Resize a registry</fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ <v>int newsize;</v>
+ </type>
+ <desc>
+ <p>Change the size of a registry.
+ </p>
+ <p><c><![CDATA[newsize]]></c> is the new size to make the registry. The
+ number will be increased to the nearest larger prime number.
+ </p>
+ <p>On success, the registry will be resized, all contents
+ rehashed, and the function will return 0. On failure, the
+ registry will be left unchanged and the function will return -1.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_close(reg)</nametext></name>
+ <fsummary>Close a registry </fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ </type>
+ <desc>
+ <p>A registry that has previously been created with
+ <c><![CDATA[ei_reg_open()]]></c> is closed, and all the objects it contains
+ are freed.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry to close.
+ </p>
+ <p>The function returns 0.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_setival(reg,key,i)</nametext></name>
+ <fsummary>Assign an integer object</fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ <v>const char *key;</v>
+ <v>int i;</v>
+ </type>
+ <desc>
+ <p>Create a key-value pair with the specified <c><![CDATA[key]]></c> and integer
+ value <c><![CDATA[i]]></c>. If an object already existed with the same
+ <c><![CDATA[key]]></c>, the new value replaces the old one. If the previous
+ value was a binary or string, it is freed with <c><![CDATA[free()]]></c>.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry where the object should be placed.
+ </p>
+ <p><c><![CDATA[key]]></c> is the name of the object.
+ </p>
+ <p><c><![CDATA[i]]></c> is the integer value to assign.
+ </p>
+ <p>The function returns 0 on success, or -1 on failure.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_setfval(reg,key,f)</nametext></name>
+ <fsummary>Assign a floating point object</fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ <v>const char *key;</v>
+ <v>double f;</v>
+ </type>
+ <desc>
+ <p>Create a key-value pair with the specified <c><![CDATA[key]]></c> and
+ floating point value <c><![CDATA[f]]></c>. If an object already existed with
+ the same <c><![CDATA[key]]></c>, the new value replaces the old one. If the
+ previous value was a binary or string, it is freed with <c><![CDATA[free()]]></c>.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry where the object should be placed.
+ </p>
+ <p><c><![CDATA[key]]></c> is the name of the object.
+ </p>
+ <p><c><![CDATA[f]]></c> is the floating point value to assign.
+ </p>
+ <p>The function returns 0 on success, or -1 on failure.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_setsval(reg,key,s)</nametext></name>
+ <fsummary>Assign a string object</fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ <v>const char *key;</v>
+ <v>const char *s;</v>
+ </type>
+ <desc>
+ <p>Create a key-value pair with the specified <c><![CDATA[key]]></c> whose
+ "value" is the specified string <c><![CDATA[s]]></c>. If an object already
+ existed with the same <c><![CDATA[key]]></c>, the new value replaces the old
+ one. If the previous value was a binary or string, it is freed
+ with <c><![CDATA[free()]]></c>.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry where the object should be placed.
+ </p>
+ <p><c><![CDATA[key]]></c> is the name of the object.
+ </p>
+ <p><c><![CDATA[s]]></c> is the string to assign. The string itself
+ must have been created through a single call to <c><![CDATA[malloc()]]></c> or
+ similar function, so that the registry can later delete it if
+ necessary by calling <c><![CDATA[free()]]></c>.
+ </p>
+ <p>The function returns 0 on success, or -1 on failure.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_setpval(reg,key,p,size)</nametext></name>
+ <fsummary>Assign a binary object</fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ <v>const char *key;</v>
+ <v>const void *p;</v>
+ <v>int size;</v>
+ </type>
+ <desc>
+ <p>Create a key-value pair with the specified <c><![CDATA[key]]></c> whose
+ "value" is the binary object pointed to by <c><![CDATA[p]]></c>. If an
+ object already existed with the same <c><![CDATA[key]]></c>, the new value
+ replaces the old one. If the previous value was a binary or
+ string, it is freed with <c><![CDATA[free()]]></c>.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry where the object should be placed.
+ </p>
+ <p><c><![CDATA[key]]></c> is the name of the object.
+ </p>
+ <p><c><![CDATA[p]]></c> is a pointer to the binary object. The object itself
+ must have been created through a single call to <c><![CDATA[malloc()]]></c> or
+ similar function, so that the registry can later delete it if
+ necessary by calling <c><![CDATA[free()]]></c>.
+ </p>
+ <p><c><![CDATA[size]]></c> is the length in bytes of the binary object.
+ </p>
+ <p>The function returns 0 on success, or -1 on failure.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_setval(reg,key,flags,v,...)</nametext></name>
+ <fsummary>Assign a value to any object type</fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ <v>const char *key;</v>
+ <v>int flags;</v>
+ <v>v (see below)</v>
+ </type>
+ <desc>
+ <p>Create a key-value pair with the specified <c><![CDATA[key]]></c> whose
+ value is specified by <c><![CDATA[v]]></c>. If an object already
+ existed with the same <c><![CDATA[key]]></c>, the new value replaces the old
+ one. If the previous value was a binary or string, it is freed
+ with <c><![CDATA[free()]]></c>.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry where the object should be placed.
+ </p>
+ <p><c><![CDATA[key]]></c> is the name of the object.
+ </p>
+ <p><c><![CDATA[flags]]></c> indicates the type of the object specified by
+ <c><![CDATA[v]]></c>. Flags must be one of EI_INT, EI_FLT, EI_STR and
+ EI_BIN, indicating whether <c><![CDATA[v]]></c> is <c><![CDATA[int]]></c>, <c><![CDATA[double]]></c>,
+ <c><![CDATA[char*]]></c> or <c><![CDATA[void*]]></c>. If <c><![CDATA[flags]]></c> is EI_BIN, then a
+ fifth argument <c><![CDATA[size]]></c> is required, indicating the size
+ in bytes of the object pointed to by <c><![CDATA[v]]></c>.
+ </p>
+ <p>If you wish to store an arbitrary pointer in the registry,
+ specify a <c><![CDATA[size]]></c> of 0. In this case, the object itself will
+ not be transferred by an <c><![CDATA[ei_reg_dump()]]></c> operation, just
+ the pointer value.
+ </p>
+ <p>The function returns 0 on success, or -1 on failure.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_getival(reg,key)</nametext></name>
+ <fsummary>Get an integer object</fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ <v>const char *key;</v>
+ </type>
+ <desc>
+ <p>Get the value associated with <c><![CDATA[key]]></c> in the
+ registry. The value must be an integer.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry where the object will be looked
+ up.
+ </p>
+ <p><c><![CDATA[key]]></c> is the name of the object to look up.
+ </p>
+ <p>On success, the function returns the value associated with <c><![CDATA[key]]></c>.
+ If the object was not found or it was not an integer
+ object, -1 is returned. To avoid problems with in-band error
+ reporting (i.e. if you cannot distinguish between -1 and a
+ valid result) use the more general function <c><![CDATA[ei_reg_getval()]]></c>
+ instead.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>double</ret><nametext>ei_reg_getfval(reg,key)</nametext></name>
+ <fsummary>Get a floating point object</fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ <v>const char *key;</v>
+ </type>
+ <desc>
+ <p>Get the value associated with <c><![CDATA[key]]></c> in the
+ registry. The value must be a floating point type.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry where the object will be looked
+ up.
+ </p>
+ <p><c><![CDATA[key]]></c> is the name of the object to look up.
+ </p>
+ <p>On success, the function returns the value associated with <c><![CDATA[key]]></c>.
+ If the object was not found or it was not a floating point
+ object, -1.0 is returned. To avoid problems with in-band error
+ reporting (i.e. if you cannot distinguish between -1.0 and a
+ valid result) use the more general function <c><![CDATA[ei_reg_getval()]]></c>
+ instead.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>const char *</ret><nametext>ei_reg_getsval(reg,key)</nametext></name>
+ <fsummary>Get a string object</fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ <v>const char *key;</v>
+ </type>
+ <desc>
+ <p>Get the value associated with <c><![CDATA[key]]></c> in the
+ registry. The value must be a string.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry where the object will be looked
+ up.
+ </p>
+ <p><c><![CDATA[key]]></c> is the name of the object to look up.
+ </p>
+ <p>On success, the function returns the value associated with
+ <c><![CDATA[key]]></c>. If the object was not found or it was not a string,
+ NULL is returned. To avoid problems with in-band error
+ reporting (i.e. if you cannot distinguish between NULL and a
+ valid result) use the more general function <c><![CDATA[ei_reg_getval()]]></c>
+ instead.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>const void *</ret><nametext>ei_reg_getpval(reg,key,size)</nametext></name>
+ <fsummary>Get a binary object</fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ <v>const char *key;</v>
+ <v>int size;</v>
+ </type>
+ <desc>
+ <p>Get the value associated with <c><![CDATA[key]]></c> in the
+ registry. The value must be a binary (pointer) type.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry where the object will be looked
+ up.
+ </p>
+ <p><c><![CDATA[key]]></c> is the name of the object to look up.
+ </p>
+ <p><c><![CDATA[size]]></c> will be initialized to contain the length in
+ bytes of the object, if it is found.
+ </p>
+ <p>On success, the function returns the value associated with
+ <c><![CDATA[key]]></c> and indicates its length in <c><![CDATA[size]]></c>.
+ If the object was not found or it was not a binary object,
+ NULL is returned. To avoid problems with in-band error
+ reporting (i.e. if you cannot distinguish between NULL and a
+ valid result) use the more general function <c><![CDATA[ei_reg_getval()]]></c>
+ instead.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_getval(reg,key,flags,v,...)</nametext></name>
+ <fsummary>Get any object</fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ <v>const char *key;</v>
+ <v>int flags;</v>
+ <v>void *v (see below)</v>
+ </type>
+ <desc>
+ <p>This is a general function for retrieving any kind of
+ object from the registry.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry where the object will be looked
+ up.
+ </p>
+ <p><c><![CDATA[key]]></c> is the name of the object to look up.
+ </p>
+ <p><c><![CDATA[flags]]></c> indicates the type of object that you are
+ looking for. If <c><![CDATA[flags]]></c> is 0, then any kind of object will
+ be returned. If <c><![CDATA[flags]]></c> is one of EI_INT, EI_FLT, EI_STR or
+ EI_BIN, then only values of that kind will be returned. The
+ buffer pointed to by <c><![CDATA[v]]></c> must be large enough to hold the return
+ data, i.e. it must be a pointer to one of <c><![CDATA[int]]></c>,
+ <c><![CDATA[double]]></c>, <c><![CDATA[char*]]></c> or <c><![CDATA[void*]]></c>, respectively. Also,
+ if <c><![CDATA[flags]]></c> is EI_BIN, then a fifth argument <c><![CDATA[int *size]]></c> is required, so that the size of the object can be
+ returned.
+ </p>
+ <p>If the function succeeds, <c><![CDATA[v]]></c> (and <c><![CDATA[size]]></c> if the
+ object is binary) will be initialized with the value associated
+ with <c><![CDATA[key]]></c>, and the function will return one of EI_INT,
+ EI_FLT, EI_STR or EI_BIN, indicating the type of object. On failure the
+ function will return -1 and the arguments will not be updated.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_markdirty(reg,key)</nametext></name>
+ <fsummary>Mark an object as dirty </fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ <v>const char *key;</v>
+ </type>
+ <desc>
+ <p>Mark a registry object as dirty. This will ensure that
+ it is included in the next backup to Mnesia. Normally this
+ operation will not be necessary since all of the normal registry
+ 'set' functions do this automatically. However if you have
+ retrieved the value of a string or binary object from the
+ registry and modified the contents, then the change will be
+ invisible to the registry and the object will be assumed to be
+ unmodified. This function allows you to make such modifications
+ and then let the registry know about them.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry containing the object.
+ </p>
+ <p><c><![CDATA[key]]></c> is the name of the object to mark.
+ </p>
+ <p>The function returns 0 on success, or -1 on failure.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_delete(reg,key)</nametext></name>
+ <fsummary>Delete an object from the registry</fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ <v>const char *key;</v>
+ </type>
+ <desc>
+ <p>Delete an object from the registry. The object is not
+ actually removed from the registry, it is only marked for later
+ removal so that on subsequent backups to Mnesia, the
+ corresponding object can be removed from the Mnesia table as
+ well. If another object is later created with the same key, the
+ object will be reused.
+ </p>
+ <p>The object will be removed from the registry after a call to
+ <c><![CDATA[ei_reg_dump()]]></c> or <c><![CDATA[ei_reg_purge()]]></c>.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry containing <c><![CDATA[key]]></c>.
+ </p>
+ <p><c><![CDATA[key]]></c> is the object to remove.
+ </p>
+ <p>If the object was found, the function returns 0 indicating
+ success. Otherwise the function returns -1.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_stat(reg,key,obuf)</nametext></name>
+ <fsummary>Get object information</fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ <v>const char *key;</v>
+ <v>struct ei_reg_stat *obuf;</v>
+ </type>
+ <desc>
+ <p>Return information about an object.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry containing the object.
+ </p>
+ <p><c><![CDATA[key]]></c> is the name of the object.
+ </p>
+ <p><c><![CDATA[obuf]]></c> is a pointer to an <c><![CDATA[ei_reg_stat]]></c> structure,
+ defined below:
+ </p>
+ <code type="none"><![CDATA[
+struct ei_reg_stat {
+ int attr;
+ int size;
+};
+ ]]></code>
+ <p>In <c><![CDATA[attr]]></c> the object's attributes are stored as the logical
+ OR of its type (one of EI_INT, EI_FLT, EI_BIN and EI_STR),
+ whether it is marked for deletion (EI_DELET) and whether it has
+ been modified since the last backup to Mnesia (EI_DIRTY).
+ </p>
+ <p>The <c><![CDATA[size]]></c> field indicates the size in bytes required to store
+ EI_STR (including the terminating 0) and EI_BIN objects, or 0
+ for EI_INT and EI_FLT.
+ </p>
+ <p>The function returns 0 and initializes <c><![CDATA[obuf]]></c> on
+ success, or returns -1 on failure.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_tabstat(reg,obuf)</nametext></name>
+ <fsummary>Get registry information</fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ <v>struct ei_reg_tabstat *obuf;</v>
+ </type>
+ <desc>
+ <p>Return information about a registry. Using information
+ returned by this function, you can see whether the size of the
+ registry is suitable for the amount of data it contains.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry to return information about.
+ </p>
+ <p><c><![CDATA[obuf]]></c> is a pointer to an <c><![CDATA[ei_reg_tabstat]]></c> structure,
+ defined below:
+ </p>
+ <code type="none"><![CDATA[
+struct ei_reg_tabstat {
+ int size;
+ int nelem;
+ int npos;
+ int collisions;
+};
+ ]]></code>
+ <p>The <c><![CDATA[size]]></c> field indicates the number of hash positions
+ in the registry. This is the number you provided when you
+ created or last resized the registry, rounded up to the nearest
+ prime.
+ </p>
+ <p><c><![CDATA[nelem]]></c> indicates the number of elements stored in the
+ registry. It includes objects that are deleted but not purged.
+ </p>
+ <p><c><![CDATA[npos]]></c> indicates the number of unique positions that are
+ occupied in the registry.
+ </p>
+ <p><c><![CDATA[collisions]]></c> indicates how many elements are sharing
+ positions in the registry.
+ </p>
+ <p>On success, the function returns 0 and <c><![CDATA[obuf]]></c> is
+ initialized to contain table statistics. On failure, the function
+ returns -1.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_dump(fd,reg,mntab,flags)</nametext></name>
+ <fsummary>Back up a registry to Mnesia</fsummary>
+ <type>
+ <v>int fd;</v>
+ <v>ei_reg *reg;</v>
+ <v>const char *mntab;</v>
+ <v>int flags;</v>
+ </type>
+ <desc>
+ <p>Dump the contents of a registry to a Mnesia table in an
+ atomic manner, i.e. either all data will be updated, or none of
+ it will. If any errors are encountered while backing up
+ the data, the entire operation is aborted.
+ </p>
+ <p><c><![CDATA[fd]]></c> is an open connection to Erlang.
+ Mnesia 3.0 or later must be running on the Erlang node.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry to back up.
+ </p>
+ <p><c><![CDATA[mntab]]></c> is the name of the Mnesia table where the backed
+ up data should be placed. If the table does not exist, it will
+ be created automatically using configurable defaults. See your
+ Mnesia documentation for information about configuring this
+ behaviour.
+ </p>
+ <p>If <c><![CDATA[flags]]></c> is 0, the backup will include only those
+ objects which have been created, modified or deleted since the
+ last backup or restore (i.e. an incremental backup). After the
+ backup, any objects that were marked dirty are now clean, and any
+ objects that had been marked for deletion are deleted.
+ </p>
+ <p>Alternatively, setting flags to EI_FORCE will cause a full
+ backup to be done, and EI_NOPURGE will cause the deleted objects
+ to be left in the registry afterwards. These can be bitwise ORed
+ together if both behaviours are desired. If EI_NOPURGE was
+ specified, you can use <c><![CDATA[ei_reg_purge()]]></c> to explicitly remove
+ the deleted items from the registry later.
+ </p>
+ <p>The function returns 0 on success, or -1 on failure.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_restore(fd,reg,mntab)</nametext></name>
+ <fsummary>Restore a registry from Mnesia</fsummary>
+ <type>
+ <v>int fd;</v>
+ <v>ei_reg *reg;</v>
+ <v>const char *mntab;</v>
+ </type>
+ <desc>
+ <p>The contents of a Mnesia table are read into the
+ registry.
+ </p>
+ <p><c><![CDATA[fd]]></c> is an open connection to Erlang.
+ Mnesia 3.0 or later must be running on the Erlang node.
+ </p>
+ <p><c><![CDATA[reg]]></c> is the registry where the data should be placed.
+ </p>
+ <p><c><![CDATA[mntab]]></c> is the name of the Mnesia table to read data
+ from.
+ </p>
+ <p>Note that only tables of a certain format can be
+ restored, i.e. those that have been created and backed up to
+ with <c><![CDATA[ei_reg_dump()]]></c>. If the registry was not empty before
+ the operation, then the contents of the table are added to the
+ contents of the registry. If the table contains objects with the
+ same keys as those already in the registry, the registry objects
+ will be overwritten with the new values. If the registry
+ contains objects that were not in the table, they will be
+ unchanged by this operation.
+ </p>
+ <p>After the restore operation, the entire contents of the
+ registry is marked as unmodified. Note that this includes any
+ objects that were modified before the restore and not
+ overwritten by the restore.
+ </p>
+ <p>The function returns 0 on success, or -1 on failure.</p>
+ </desc>
+ </func>
+ <func>
+ <name><ret>int</ret><nametext>ei_reg_purge(reg)</nametext></name>
+ <fsummary>Remove deleted objects</fsummary>
+ <type>
+ <v>ei_reg *reg;</v>
+ </type>
+ <desc>
+ <p>Remove all objects marked for deletion. When objects
+ are deleted with <c><![CDATA[ei_reg_delete()]]></c> they are not actually
+ removed from the registry, only marked for later removal. This
+ is so that on a subsequent backup to Mnesia, the
+ objects can also be removed from the Mnesia table. If you are
+ not backing up to Mnesia then you may wish to remove the objects
+ manually with this function.
+ </p>
+ <p><c><![CDATA[reg]]></c> is a registry containing objects marked for
+ deletion.
+ </p>
+ <p>The function returns 0 on success, or -1 on failure.</p>
+ </desc>
+ </func>
+ </funcs>
+</cref>
+
diff --git a/lib/erl_interface/doc/src/warning.gif b/lib/erl_interface/doc/src/warning.gif
new file mode 100644
index 0000000000..96af52360e
--- /dev/null
+++ b/lib/erl_interface/doc/src/warning.gif
Binary files differ
diff --git a/lib/erl_interface/include/ei.h b/lib/erl_interface/include/ei.h
new file mode 100644
index 0000000000..01272244e1
--- /dev/null
+++ b/lib/erl_interface/include/ei.h
@@ -0,0 +1,785 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef EI_H
+#define EI_H
+
+#define EI_HAVE_TIMEOUT 1 /* Flag to user code that we have them */
+#define USE_EI_UNDOCUMENTED /* Want declarations for undocumented */
+
+/************************************************************************/
+/* This file defines the complete interface to ei */
+/************************************************************************/
+
+/* -------------------------------------------------------------------- */
+/* Include types needed below */
+/* -------------------------------------------------------------------- */
+
+#if defined(__WIN32__)
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+#endif
+
+#include <stdio.h> /* Need type FILE */
+#include <errno.h> /* Need EHOSTUNREACH, ENOMEM, ... */
+
+#if !defined(__WIN32__) && !defined(VXWORKS) || (defined(VXWORKS) && defined(HAVE_SENS))
+# include <netdb.h>
+#endif
+
+
+/* -------------------------------------------------------------------- */
+/* Defines part of API */
+/* -------------------------------------------------------------------- */
+
+/*
+ * Some error codes might be missing, so here's a backstop definitions
+ * of the ones we use with `erl_errno':
+ */
+
+#ifndef EMSGSIZE /* Message too long */
+#define EMSGSIZE EIO
+#endif
+
+#ifndef ETIMEDOUT /* Connection timed out */
+#define ETIMEDOUT EIO
+#endif
+
+#ifndef EHOSTUNREACH /* No route to host */
+#define EHOSTUNREACH EIO
+#endif
+
+/* FIXME just a few are documented, does it mean they can't be returned? */
+
+#define ERL_ERROR -1 /* Error of some kind */
+#define ERL_NO_DAEMON -2 /* No contact with EPMD */
+#define ERL_NO_PORT -3 /* No port received from EPMD */
+#define ERL_CONNECT_FAIL -4 /* Connect to Erlang Node failed */
+#define ERL_TIMEOUT -5 /* A timeout has expired */
+#define ERL_NO_REMOTE -6 /* Cannot execute rsh */
+
+#define ERL_TICK 0
+#define ERL_MSG 1
+
+#define ERL_NO_TIMEOUT -1
+
+/* these are the control message types */
+#define ERL_LINK 1
+#define ERL_SEND 2
+#define ERL_EXIT 3
+#define ERL_UNLINK 4
+#define ERL_NODE_LINK 5
+#define ERL_REG_SEND 6
+#define ERL_GROUP_LEADER 7
+#define ERL_EXIT2 8
+#define ERL_PASS_THROUGH 'p'
+
+/* new ones for tracing, from Kenneth */
+#define ERL_SEND_TT 12
+#define ERL_EXIT_TT 13
+#define ERL_REG_SEND_TT 16
+#define ERL_EXIT2_TT 18
+
+
+/* -------------------------------------------------------------------- */
+/* Defines used for ei_get_type_internal() output */
+/* -------------------------------------------------------------------- */
+/*
+ * these are the term type indicators used in
+ * the external (distribution) format
+ */
+
+/* FIXME we don't want to export these..... */
+
+#define ERL_SMALL_INTEGER_EXT 'a'
+#define ERL_INTEGER_EXT 'b'
+#define ERL_FLOAT_EXT 'c'
+#define ERL_ATOM_EXT 'd'
+#define ERL_REFERENCE_EXT 'e'
+#define ERL_NEW_REFERENCE_EXT 'r'
+#define ERL_PORT_EXT 'f'
+#define ERL_PID_EXT 'g'
+#define ERL_SMALL_TUPLE_EXT 'h'
+#define ERL_LARGE_TUPLE_EXT 'i'
+#define ERL_NIL_EXT 'j'
+#define ERL_STRING_EXT 'k'
+#define ERL_LIST_EXT 'l'
+#define ERL_BINARY_EXT 'm'
+#define ERL_SMALL_BIG_EXT 'n'
+#define ERL_LARGE_BIG_EXT 'o'
+#define ERL_NEW_FUN_EXT 'p'
+#define ERL_FUN_EXT 'u'
+
+#define ERL_NEW_CACHE 'N' /* c nodes don't know these two */
+#define ERL_CACHED_ATOM 'C'
+
+
+/* -------------------------------------------------------------------- */
+/* Define the erl_errno macro */
+/* -------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * GCC's attributes are too useful to not use. Other compilers
+ * just lose opportunities to optimize and warn.
+ */
+#if !defined(__GNUC__) || __GNUC__ < 2
+# define __attribute__(foo) /* nothing */
+#endif
+
+/*
+ * Define the 'erl_errno' facility. Unfortunately this lives on in
+ * the 'ei' interface as well.... :-(
+ */
+
+#if defined(_REENTRANT) || defined(VXWORKS) || defined(__WIN32__)
+
+/* 'erl_errno' as a function return value */
+volatile int* __erl_errno_place(void) __attribute__ ((__const__));
+
+#define erl_errno (*__erl_errno_place ())
+
+#else /* !_REENTRANT && !VXWORKS && !__WIN32__ */
+
+extern volatile int __erl_errno;
+
+#define erl_errno __erl_errno
+
+#endif /* !_REENTRANT && !VXWORKS && !__WIN32__ */
+
+
+/* -------------------------------------------------------------------- */
+/* Type definitions */
+/* -------------------------------------------------------------------- */
+
+/*
+ * To avoid confusion about the MAXHOSTNAMELEN when compiling the
+ * library and when using the library we set a value that we use
+ */
+
+#define EI_MAXHOSTNAMELEN 64
+#define EI_MAXALIVELEN 63
+#define EI_MAX_COOKIE_SIZE 512
+#define MAXATOMLEN 255
+#define MAXNODELEN EI_MAXALIVELEN+1+EI_MAXHOSTNAMELEN
+
+/* a pid */
+typedef struct {
+ char node[MAXATOMLEN+1];
+ unsigned int num;
+ unsigned int serial;
+ unsigned int creation;
+} erlang_pid;
+
+/* a port */
+typedef struct {
+ char node[MAXATOMLEN+1];
+ unsigned int id;
+ unsigned int creation;
+} erlang_port;
+
+/* a ref */
+typedef struct {
+ char node[MAXATOMLEN+1];
+ int len;
+ unsigned int n[3];
+ unsigned int creation;
+} erlang_ref;
+
+/* a trace token */
+typedef struct {
+ long serial;
+ long prev;
+ erlang_pid from;
+ long label;
+ long flags;
+} erlang_trace;
+
+/* a message */
+typedef struct {
+ long msgtype;
+ erlang_pid from;
+ erlang_pid to;
+ char toname[MAXATOMLEN+1];
+ char cookie[MAXATOMLEN+1];
+ erlang_trace token;
+} erlang_msg;
+
+/* a fun */
+typedef struct {
+ long arity;
+ char module[MAXATOMLEN+1];
+ char md5[16];
+ long index;
+ long old_index;
+ long uniq;
+ long n_free_vars;
+ erlang_pid pid;
+ long free_var_len;
+ char* free_vars;
+} erlang_fun;
+
+/* a big */
+typedef struct {
+ unsigned int arity;
+ int is_neg;
+ void *digits;
+} erlang_big;
+
+typedef struct {
+ char ei_type;
+ int arity;
+ int size;
+ union {
+ long i_val;
+ double d_val;
+ char atom_name[MAXATOMLEN+1];
+ erlang_pid pid;
+ erlang_port port;
+ erlang_ref ref;
+ } value;
+} ei_term;
+
+/* XXX */
+
+typedef struct {
+ char ipadr[4]; /* stored in network byte order */
+ char nodename[MAXNODELEN+1];
+} ErlConnect;
+
+typedef struct ei_cnode_s {
+ char thishostname[EI_MAXHOSTNAMELEN+1];
+ char thisnodename[MAXNODELEN+1];
+ char thisalivename[EI_MAXALIVELEN+1];
+/* Currently this_ipaddr isn't used */
+/* struct in_addr this_ipaddr; */
+ char ei_connect_cookie[EI_MAX_COOKIE_SIZE+1];
+ short creation;
+ erlang_pid self;
+} ei_cnode;
+
+typedef struct in_addr *Erl_IpAddr;
+
+
+/* A dynamic version of ei XX */
+
+typedef struct ei_x_buff_TAG {
+ char* buff;
+ int buffsz;
+ int index;
+} ei_x_buff;
+
+
+/* -------------------------------------------------------------------- */
+/* Function definitions (listed in same order as documentation) */
+/* -------------------------------------------------------------------- */
+
+/* Handle the connection */
+
+int ei_connect_init(ei_cnode* ec, const char* this_node_name,
+ const char *cookie, short creation);
+int ei_connect_xinit (ei_cnode* ec, const char *thishostname,
+ const char *thisalivename, const char *thisnodename,
+ Erl_IpAddr thisipaddr, const char *cookie,
+ const short creation);
+
+int ei_connect(ei_cnode* ec, char *nodename);
+int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms);
+int ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename);
+int ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned ms);
+
+int ei_receive(int fd, unsigned char *bufp, int bufsize);
+int ei_receive_tmo(int fd, unsigned char *bufp, int bufsize, unsigned ms);
+int ei_receive_msg(int fd, erlang_msg* msg, ei_x_buff* x);
+int ei_receive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned ms);
+int ei_xreceive_msg(int fd, erlang_msg* msg, ei_x_buff* x);
+int ei_xreceive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned ms);
+
+int ei_send(int fd, erlang_pid* to, char* buf, int len);
+int ei_send_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned ms);
+int ei_reg_send(ei_cnode* ec, int fd, char *server_name, char* buf, int len);
+int ei_reg_send_tmo(ei_cnode* ec, int fd, char *server_name, char* buf, int len, unsigned ms);
+
+int ei_rpc(ei_cnode* ec, int fd, char *mod, char *fun,
+ const char* inbuf, int inbuflen, ei_x_buff* x);
+int ei_rpc_to(ei_cnode* ec, int fd, char *mod, char *fun,
+ const char* buf, int len);
+int ei_rpc_from(ei_cnode* ec, int fd, int timeout, erlang_msg* msg,
+ ei_x_buff* x);
+
+int ei_publish(ei_cnode* ec, int port);
+int ei_publish_tmo(ei_cnode* ec, int port, unsigned ms);
+int ei_accept(ei_cnode* ec, int lfd, ErlConnect *conp);
+int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms);
+int ei_unpublish(ei_cnode* ec);
+int ei_unpublish_tmo(const char *alive, unsigned ms);
+
+const char *ei_thisnodename(const ei_cnode* ec);
+const char *ei_thishostname(const ei_cnode* ec);
+const char *ei_thisalivename(const ei_cnode* ec);
+
+erlang_pid *ei_self(ei_cnode* ec);
+
+void ei_set_compat_rel(unsigned rel);
+
+/*
+ * We have erl_gethost*() so we include ei versions as well.
+ */
+
+#if defined(VXWORKS)
+
+extern int h_errno;
+
+/*
+ * We need these definitions - if the user has SENS then he gets them
+ * from netdb.h, otherwise we define them ourselves.
+ *
+ * If you are getting "multiple definition" errors here,
+ * make sure you have included <netdb.h> BEFORE "erl_interface.h"
+ * or define HAVE_SENS in your CFLAGS.
+ */
+
+#if !defined(HAVE_SENS) && !defined(HOST_NOT_FOUND) /* just in case */
+
+struct hostent {
+ char *h_name; /* official name of host */
+ char **h_aliases; /* alias list */
+ int h_addrtype; /* host address type */
+ int h_length; /* length of address */
+ char **h_addr_list; /* list of addresses from name server */
+#define h_addr h_addr_list[0] /* address, for backward compatiblity */
+ unsigned int unused; /* SENS defines this as ttl */
+};
+
+#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */
+#define TRY_AGAIN 2 /* Non-Authoritive Host not found, or SERVERFAIL */
+#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+#define NO_DATA 4 /* Valid name, no data record of requested type */
+#define NO_ADDRESS NO_DATA /* no address, look for MX record */
+
+#endif /* !HAVE_SENS && !HOST_NOT_FOUND */
+#endif /* VXWORKS */
+
+
+struct hostent *ei_gethostbyname(const char *name);
+struct hostent *ei_gethostbyaddr(const char *addr, int len, int type);
+struct hostent *ei_gethostbyname_r(const char *name,
+ struct hostent *hostp,
+ char *buffer,
+ int buflen,
+ int *h_errnop);
+struct hostent *ei_gethostbyaddr_r(const char *addr,
+ int length,
+ int type,
+ struct hostent *hostp,
+ char *buffer,
+ int buflen,
+ int *h_errnop);
+
+
+/* Encode/decode functions */
+
+int ei_encode_version(char *buf, int *index);
+int ei_x_encode_version(ei_x_buff* x);
+int ei_encode_long(char *buf, int *index, long p);
+int ei_x_encode_long(ei_x_buff* x, long n);
+int ei_encode_ulong(char *buf, int *index, unsigned long p);
+int ei_x_encode_ulong(ei_x_buff* x, unsigned long n);
+int ei_encode_double(char *buf, int *index, double p);
+int ei_x_encode_double(ei_x_buff* x, double dbl);
+int ei_encode_boolean(char *buf, int *index, int p);
+int ei_x_encode_boolean(ei_x_buff* x, int p);
+int ei_encode_char(char *buf, int *index, char p);
+int ei_x_encode_char(ei_x_buff* x, char p);
+int ei_encode_string(char *buf, int *index, const char *p);
+int ei_encode_string_len(char *buf, int *index, const char *p, int len);
+int ei_x_encode_string(ei_x_buff* x, const char* s);
+int ei_x_encode_string_len(ei_x_buff* x, const char* s, int len);
+int ei_encode_atom(char *buf, int *index, const char *p);
+int ei_encode_atom_len(char *buf, int *index, const char *p, int len);
+int ei_x_encode_atom(ei_x_buff* x, const char* s);
+int ei_x_encode_atom_len(ei_x_buff* x, const char* s, int len);
+int ei_encode_binary(char *buf, int *index, const void *p, long len);
+int ei_x_encode_binary(ei_x_buff* x, const void* s, int len);
+int ei_encode_pid(char *buf, int *index, const erlang_pid *p);
+int ei_x_encode_pid(ei_x_buff* x, const erlang_pid* pid);
+int ei_encode_fun(char* buf, int* index, const erlang_fun* p);
+int ei_x_encode_fun(ei_x_buff* x, const erlang_fun* fun);
+int ei_encode_port(char *buf, int *index, const erlang_port *p);
+int ei_x_encode_port(ei_x_buff* x, const erlang_port *p);
+int ei_encode_ref(char *buf, int *index, const erlang_ref *p);
+int ei_x_encode_ref(ei_x_buff* x, const erlang_ref *p);
+int ei_encode_term(char *buf, int *index, void *t); /* ETERM* actually */
+int ei_x_encode_term(ei_x_buff* x, void* t);
+int ei_encode_trace(char *buf, int *index, const erlang_trace *p);
+int ei_x_encode_trace(ei_x_buff* x, const erlang_trace *p);
+int ei_encode_tuple_header(char *buf, int *index, int arity);
+int ei_x_encode_tuple_header(ei_x_buff* x, long n);
+int ei_encode_list_header(char *buf, int *index, int arity);
+int ei_x_encode_list_header(ei_x_buff* x, long n);
+#define ei_encode_empty_list(buf,i) ei_encode_list_header(buf,i,0)
+int ei_x_encode_empty_list(ei_x_buff* x);
+
+/*
+ * ei_get_type() returns the type and "size" of the item at
+ * buf[index]. For strings and atoms, size is the number of characters
+ * not including the terminating 0. For binaries, size is the number
+ * of bytes. For lists and tuples, size is the arity of the
+ * object. For other types, size is 0. In all cases, index is left
+ * unchanged.
+ */
+
+int ei_get_type(const char *buf, const int *index, int *type, int *size);
+int ei_get_type_internal(const char *buf, const int *index, int *type,
+ int *size);
+
+/* Step through buffer, decoding the given type into the buffer
+ * provided. On success, 0 is returned and index is updated to point
+ * to the start of the next item in the buffer. If the type of item at
+ * buf[index] is not the requested type, -1 is returned and index is
+ * not updated. The buffer provided by the caller must be sufficiently
+ * large to contain the decoded object.
+ */
+int ei_decode_version(const char *buf, int *index, int *version);
+int ei_decode_long(const char *buf, int *index, long *p);
+int ei_decode_ulong(const char *buf, int *index, unsigned long *p);
+int ei_decode_double(const char *buf, int *index, double *p);
+int ei_decode_boolean(const char *buf, int *index, int *p);
+int ei_decode_char(const char *buf, int *index, char *p);
+int ei_decode_string(const char *buf, int *index, char *p);
+int ei_decode_atom(const char *buf, int *index, char *p);
+int ei_decode_binary(const char *buf, int *index, void *p, long *len);
+int ei_decode_fun(const char* buf, int* index, erlang_fun* p);
+void free_fun(erlang_fun* f);
+int ei_decode_pid(const char *buf, int *index, erlang_pid *p);
+int ei_decode_port(const char *buf, int *index, erlang_port *p);
+int ei_decode_ref(const char *buf, int *index, erlang_ref *p);
+int ei_decode_term(const char *buf, int *index, void *t); /* ETERM** actually */
+int ei_decode_trace(const char *buf, int *index, erlang_trace *p);
+int ei_decode_tuple_header(const char *buf, int *index, int *arity);
+int ei_decode_list_header(const char *buf, int *index, int *arity);
+
+/*
+ * ei_decode_ei_term() returns 1 if term is decoded, 0 if term is OK,
+ * but not decoded here and -1 if something is wrong. ONLY changes
+ * index if term is decoded (return value 1)!
+ */
+
+int ei_decode_ei_term(const char* buf, int* index, ei_term* term);
+
+
+/*
+ * ei_print_term to print out a binary coded term
+ */
+
+int ei_print_term(FILE *fp, const char* buf, int* index);
+int ei_s_print_term(char** s, const char* buf, int* index);
+
+/*
+ * format to build binary format terms a bit like printf
+ */
+
+int ei_x_format(ei_x_buff* x, const char* fmt, ...);
+int ei_x_format_wo_ver(ei_x_buff* x, const char *fmt, ...);
+
+int ei_x_new(ei_x_buff* x);
+int ei_x_new_with_version(ei_x_buff* x);
+int ei_x_free(ei_x_buff* x);
+int ei_x_append(ei_x_buff* x, const ei_x_buff* x2);
+int ei_x_append_buf(ei_x_buff* x, const char* buf, int len);
+int ei_skip_term(const char* buf, int* index);
+
+/***************************************************************************
+ *
+ * Hash types needed by registry types
+ *
+ ***************************************************************************/
+
+#define EI_SMALLKEY 32
+
+typedef struct bucket_s {
+ int rawhash;
+ const char *key;
+ char keybuf[EI_SMALLKEY];
+ const void *value;
+ struct bucket_s *next;
+} ei_bucket;
+
+/* users of the package declare variables as pointers to this. */
+typedef struct {
+ ei_bucket **tab;
+ int (*hash)(const char *); /* hash function for this table */
+ int size; /* size of table */
+ int nelem; /* nr elements */
+ int npos; /* nr occupied positions */
+ ei_bucket *freelist; /* reuseable freed buckets */
+} ei_hash;
+
+
+/***************************************************************************
+ *
+ * Registry defines, types, functions
+ *
+ ***************************************************************************/
+
+/* -------------------------------------------------------------------- */
+/* XXXXXXXXXXX */
+/* -------------------------------------------------------------------- */
+
+/* registry object attributes */
+#define EI_DIRTY 0x01 /* dirty bit (object value differs from backup) */
+#define EI_DELET 0x02 /* object is deleted */
+#define EI_INT 0x10 /* object is an integer */
+#define EI_FLT 0x20 /* object is a float */
+#define EI_STR 0x40 /* object is a string */
+#define EI_BIN 0x80 /* object is a binary, i.e. pointer to arbitrary type */
+
+
+/* -------------------------------------------------------------------- */
+/* XXXXXXXXXXX */
+/* -------------------------------------------------------------------- */
+
+typedef struct ei_reg_inode {
+ int attr;
+ int size;
+ union {
+ long i;
+ double f;
+ char *s;
+ void *p;
+ } val;
+ struct ei_reg_inode *next;
+} ei_reg_obj;
+
+typedef struct {
+ ei_reg_obj *freelist;
+ ei_hash *tab;
+} ei_reg;
+
+struct ei_reg_stat {
+ int attr; /* object attributes (see above) */
+ int size; /* size in bytes (for STR and BIN) 0 for others */
+};
+
+struct ei_reg_tabstat {
+ int size; /* size of table */
+ int nelem; /* number of stored elements */
+ int npos; /* number of occupied positions */
+ int collisions; /* number of positions with more than one element */
+};
+
+
+/* -------------------------------------------------------------------- */
+/* XXXXXXXXXXX */
+/* -------------------------------------------------------------------- */
+
+/* FIXME move comments to source */
+
+/* open / close registry. On open, a descriptor is returned that must
+ * be specified in all subsequent calls to registry functions. You can
+ * open as many registries as you like.
+ */
+ei_reg *ei_reg_open(int size);
+int ei_reg_resize(ei_reg *oldreg, int newsize);
+int ei_reg_close(ei_reg *reg);
+
+/* set values... these routines assign values to keys. If the key
+ * exists, the previous value is discarded and the new one replaces
+ * it.
+ *
+ * BIN objects require an additional argument indicating the size in
+ * bytes of the stored object. This will be used when the object is
+ * backed up, since it will need to be copied at that time. Remember
+ * also that pointers are process-space specific and it is not
+ * meaningful to back them up for later recall. If you are storing
+ * binary objects for backup, make sure that they are self-contained
+ * (without references to other objects).
+ *
+ * On success the function returns 0, otherwise a value
+ * indicating the reason for failure will be returned.
+ */
+int ei_reg_setival(ei_reg *reg, const char *key, long i);
+int ei_reg_setfval(ei_reg *reg, const char *key, double f);
+int ei_reg_setsval(ei_reg *reg, const char *key, const char *s);
+int ei_reg_setpval(ei_reg *reg, const char *key, const void *p, int size);
+
+/* general set function (specifiy type via flags)
+ * optional arguments are as for equivalent type-specific function,
+ * i.e.:
+ * ei_reg_setval(fd, path, EI_INT, int i);
+ * ei_reg_setval(fd, path, EI_FLT, float f);
+ * ei_reg_setval(fd, path, EI_STR, const char *s);
+ * ei_reg_setval(fd, path, EI_BIN, const void *p, int size);
+ */
+int ei_reg_setval(ei_reg *reg, const char *key, int flags, ...);
+
+/* get value of specific type object */
+/* warning: it may be difficult to detect errors when using these
+ * functions, since the error values are returned "in band"
+ */
+long ei_reg_getival(ei_reg *reg, const char *key);
+double ei_reg_getfval(ei_reg *reg, const char *key);
+const char *ei_reg_getsval(ei_reg *reg, const char *key);
+const void *ei_reg_getpval(ei_reg *reg, const char *key, int *size);
+
+/* get value of any type object (must specify)
+ * Retrieve a value from an object. The type of value expected and a
+ * pointer to a large enough buffer must be provided. flags must be
+ * set to the appropriate type (see type constants above) and the
+ * object type must match. If (flags == 0) the pointer is *assumed* to
+ * be of the correct type for the object. In any case, the actual
+ * object type is always returned on success.
+ *
+ * The argument following flags must be one of int*, double*, const
+ * char** and const void**.
+ *
+ * for BIN objects an int* is needed to return the size of the object, i.e.
+ * int ei_reg_getval(ei_reg *reg, const char *path, int flags, void **p, int *size);
+ */
+int ei_reg_getval(ei_reg *reg, const char *key, int flags, ...);
+
+/* mark the object as dirty. Normally this operation will not be
+ * necessary, as it is done automatically by all of the above 'set'
+ * functions. However, if you modify the contents of an object pointed
+ * to by a STR or BIN object, then the registry will not be aware of
+ * the change. As a result, the object may be missed on a subsequent
+ * backup operation. Use this function to set the dirty bit on the
+ * object.
+ */
+int ei_reg_markdirty(ei_reg *reg, const char *key);
+
+/* remove objects. The value, if any, is discarded. For STR and BIN
+ * objects, the object itself is removed using free(). */
+int ei_reg_delete(ei_reg *reg, const char *key);
+
+/* get information about an object */
+int ei_reg_stat(ei_reg *reg, const char *key, struct ei_reg_stat *obuf);
+
+/* get information about table */
+int ei_reg_tabstat(ei_reg *reg, struct ei_reg_tabstat *obuf);
+
+/* dump to / restore from backup */
+/* fd is open descriptor to Erlang, mntab is Mnesia table name */
+/* flags here: */
+#define EI_FORCE 0x1 /* dump all records (not just dirty ones) */
+#define EI_NOPURGE 0x2 /* don't purge deleted records */
+int ei_reg_dump(int fd, ei_reg *reg, const char *mntab, int flags);
+int ei_reg_restore(int fd, ei_reg *reg, const char *mntab);
+int ei_reg_purge(ei_reg *reg);
+
+
+/* -------------------------------------------------------------------- */
+/* Encoding/decoding bugnums to GNU MP format */
+/* -------------------------------------------------------------------- */
+
+/* If the user included <gmp.h> we supply some more functions */
+
+#if defined(__GNU_MP_VERSION) \
+ && __GNU_MP_VERSION == 4 && __GNU_MP_VERSION_MINOR >= 1
+
+int ei_decode_bignum(const char *buf, int *index, mpz_t obj);
+int ei_encode_bignum(char *buf, int *index, mpz_t obj);
+int ei_x_encode_bignum(ei_x_buff *x, mpz_t obj);
+
+#endif /* __GNU_MP_VERSION */
+
+/* -------------------------------------------------------------------- */
+/* Function definitions not documented FIXME */
+/* -------------------------------------------------------------------- */
+
+/* FIXME replace this primitive type size code */
+
+#ifdef __WIN32__
+#define EI_LONGLONG __int64
+#define EI_ULONGLONG unsigned __int64
+#else
+#ifndef VXWORKS
+#define EI_LONGLONG long long
+#define EI_ULONGLONG unsigned long long
+#endif
+#endif
+
+#ifndef VXWORKS
+int ei_decode_longlong(const char *buf, int *index, EI_LONGLONG *p);
+int ei_decode_ulonglong(const char *buf, int *index, EI_ULONGLONG *p);
+int ei_encode_longlong(char *buf, int *index, EI_LONGLONG p);
+int ei_encode_ulonglong(char *buf, int *index, EI_ULONGLONG p);
+int ei_x_encode_longlong(ei_x_buff* x, EI_LONGLONG n);
+int ei_x_encode_ulonglong(ei_x_buff* x, EI_ULONGLONG n);
+#endif
+
+#ifdef USE_EI_UNDOCUMENTED
+
+/*
+ * Decode a list of integers into an integer array (i.e. even if it is
+ * encoded as a string). count gets number of items in array.
+ * See "decode_intlist.c".
+ */
+
+int ei_decode_intlist(const char *buf, int *index, long *a, int *count);
+
+/*
+ * FIXME: used in IC, document?
+ * bufp = address of pointer to dynamically allocated buffer - may be reallocated by
+ * this function if it is too small for the message
+ * bufsz = in/out value: in=user buffer size, out=new buffer size
+ * msglen = nr bytes in received message
+ */
+int ei_receive_encoded(int fd, char **bufp, int *bufsz, erlang_msg *to,
+ int *msglen);
+int ei_receive_encoded_tmo(int fd, char **bufp, int *bufsz, erlang_msg *to,
+ int *msglen, unsigned ms);
+int ei_send_encoded(int fd, const erlang_pid *to, char *msg, int msglen);
+int ei_send_encoded_tmo(int fd, const erlang_pid *to, char *msg, int msglen,
+ unsigned ms);
+int ei_send_reg_encoded(int fd, const erlang_pid *from, const char *to,
+ char *msg, int msglen);
+int ei_send_reg_encoded_tmo(int fd, const erlang_pid *from, const char *to,
+ char *msg, int msglen, unsigned ms);
+
+/*
+ * Bacward compatibility with old undocumented but used interface...
+ * FIXME use wrapper function instead?!
+ */
+#define ei_send_encoded_timeout(Fd,To,Msg,MsgLen,Ms) \
+ ei_send_encoded_tmo((Fd),(To),(Msg),(MsgLen),(Ms))
+#define ei_send_reg_encoded_timeout(Fd,From,To,Msg,MsgLen,Ms) \
+ ei_send_reg_encoded_tmo((Fd),(From),(To),(Msg),(MsgLen),(Ms))
+
+
+/* FIXME: is this really the best way to handle bignums? */
+int ei_encode_big(char *buf, int *index, erlang_big* big);
+int ei_x_encode_big(ei_x_buff* x, erlang_big* big);
+int ei_decode_big(const char *buf, int *index, erlang_big* p);
+int ei_big_comp(erlang_big *x, erlang_big *y);
+int ei_big_to_double(erlang_big *b, double *resp);
+int ei_small_to_big(int s, erlang_big *b);
+erlang_big *ei_alloc_big(unsigned int arity);
+void ei_free_big(erlang_big *b);
+
+#endif /* USE_EI_UNDOCUMENTED */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EI_H */
diff --git a/lib/erl_interface/include/ei_connect.h b/lib/erl_interface/include/ei_connect.h
new file mode 100644
index 0000000000..02880e197c
--- /dev/null
+++ b/lib/erl_interface/include/ei_connect.h
@@ -0,0 +1,26 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2003-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef EI_CONNECT_H
+#define EI_CONNECT_H
+
+/* Dummy for now.... */
+
+#include "ei.h"
+
+#endif /* EI_CONNECT_H */
diff --git a/lib/erl_interface/include/eicode.h b/lib/erl_interface/include/eicode.h
new file mode 100644
index 0000000000..c35489e890
--- /dev/null
+++ b/lib/erl_interface/include/eicode.h
@@ -0,0 +1,26 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2003-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef EICODE_H
+#define EICODE_H
+
+/* Dummy for now.... */
+
+#include "ei.h"
+
+#endif /* EICODE_H */
diff --git a/lib/erl_interface/include/erl_interface.h b/lib/erl_interface/include/erl_interface.h
new file mode 100644
index 0000000000..1c4a94700d
--- /dev/null
+++ b/lib/erl_interface/include/erl_interface.h
@@ -0,0 +1,449 @@
+/*
+ * %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%
+ */
+#ifndef _ERL_INTERFACE_H
+#define _ERL_INTERFACE_H
+
+/************************************************************************/
+/* This file defines the complete interface to erl_interface */
+/* Note: the 'ei' interface is the prefered C API. */
+/************************************************************************/
+
+/* FIXME only include if needed? */
+
+#include "ei.h" /* ei is the base */
+
+/* -------------------------------------------------------------------- */
+/* Public defines */
+/* -------------------------------------------------------------------- */
+
+#define ERL_COMPOUND (1 << 7)
+
+#define ERL_UNDEF 0
+#define ERL_INTEGER 1
+#define ERL_U_INTEGER 2 /* unsigned int */
+#define ERL_ATOM 3
+#define ERL_PID 4
+#define ERL_PORT 5
+#define ERL_REF 6
+#define ERL_CONS (7 | ERL_COMPOUND)
+#define ERL_LIST ERL_CONS
+#define ERL_NIL 8
+#define ERL_EMPTY_LIST ERL_NIL
+#define ERL_TUPLE (9 | ERL_COMPOUND)
+#define ERL_BINARY 10
+#define ERL_FLOAT 11
+#define ERL_VARIABLE (12 | ERL_COMPOUND) /* used in patterns */
+#define ERL_SMALL_BIG 13
+#define ERL_U_SMALL_BIG 14
+#define ERL_FUNCTION (15 | ERL_COMPOUND)
+#define ERL_BIG 16
+#define ERL_LONGLONG 17
+#define ERL_U_LONGLONG 18
+
+
+#define ERL_TYPE(x) (ERL_HEADER(x)->type)
+
+/* FIXME some macros left in erl_eterm.h should probably be documented */
+
+#define ERL_IS_INTEGER(x) (ERL_TYPE(x) == ERL_INTEGER)
+#define ERL_IS_UNSIGNED_INTEGER(x) (ERL_TYPE(x) == ERL_U_INTEGER)
+#define ERL_IS_LONGLONG(x) (ERL_TYPE(x) == ERL_LONGLONG)
+#define ERL_IS_UNSIGNED_LONGLONG(x) (ERL_TYPE(x) == ERL_U_LONGLONG)
+#define ERL_IS_FLOAT(x) (ERL_TYPE(x) == ERL_FLOAT)
+#define ERL_IS_ATOM(x) (ERL_TYPE(x) == ERL_ATOM)
+#define ERL_IS_PID(x) (ERL_TYPE(x) == ERL_PID)
+#define ERL_IS_PORT(x) (ERL_TYPE(x) == ERL_PORT)
+#define ERL_IS_REF(x) (ERL_TYPE(x) == ERL_REF)
+#define ERL_IS_TUPLE(x) (ERL_TYPE(x) == ERL_TUPLE)
+#define ERL_IS_BINARY(x) (ERL_TYPE(x) == ERL_BINARY)
+#define ERL_IS_NIL(x) (ERL_TYPE(x) == ERL_NIL)
+#define ERL_IS_EMPTY_LIST(x) ERL_IS_NIL(x)
+#define ERL_IS_CONS(x) (ERL_TYPE(x) == ERL_CONS)
+#define ERL_IS_LIST(x) (ERL_IS_CONS(x) || ERL_IS_EMPTY_LIST(x))
+
+/*
+ * Macros used for XXXX
+ */
+
+#define ERL_HEADER(x) ((Erl_Header *)x)
+#define ERL_COUNT(x) (ERL_HEADER(x)->count)
+
+/*
+ * Macros used for retrieving values from Erlang terms.
+ */
+
+#define ERL_INT_VALUE(x) ((x)->uval.ival.i)
+#define ERL_INT_UVALUE(x) ((x)->uval.uival.u)
+#define ERL_LL_VALUE(x) ((x)->uval.llval.i)
+#define ERL_LL_UVALUE(x) ((x)->uval.ullval.u)
+
+#define ERL_FLOAT_VALUE(x) ((x)->uval.fval.f)
+
+#define ERL_ATOM_PTR(x) ((x)->uval.aval.a)
+#define ERL_ATOM_SIZE(x) ((x)->uval.aval.len)
+
+#define ERL_PID_NODE(x) ((x)->uval.pidval.node)
+#define ERL_PID_NUMBER(x) ((x)->uval.pidval.number)
+#define ERL_PID_SERIAL(x) ((x)->uval.pidval.serial)
+#define ERL_PID_CREATION(x) ((x)->uval.pidval.creation)
+
+#define ERL_PORT_NODE(x) ((x)->uval.portval.node)
+#define ERL_PORT_NUMBER(x) ((x)->uval.portval.number)
+#define ERL_PORT_CREATION(x) ((x)->uval.portval.creation)
+
+#define ERL_REF_NODE(x) ((x)->uval.refval.node)
+#define ERL_REF_NUMBER(x) ((x)->uval.refval.n[0])
+#define ERL_REF_NUMBERS(x) ((x)->uval.refval.n)
+#define ERL_REF_LEN(x) ((x)->uval.refval.len)
+#define ERL_REF_CREATION(x) ((x)->uval.refval.creation)
+
+#define ERL_TUPLE_SIZE(x) ((x)->uval.tval.size)
+
+/* NOTE!!! This is 0-based!! (first item is number 0)
+ * Note too that element/2 (in Erlang) and
+ * erl_element() are both 1-based.
+ */
+#define ERL_TUPLE_ELEMS(x) ((x)->uval.tval.elems)
+#define ERL_TUPLE_ELEMENT(x, i) (ERL_TUPLE_ELEMS(x)[(i)])
+
+#define ERL_BIN_SIZE(x) ((x)->uval.bval.size)
+#define ERL_BIN_PTR(x) ((x)->uval.bval.b)
+
+#define ERL_CONS_HEAD(x) ((x)->uval.lval.head)
+#define ERL_CONS_TAIL(x) ((x)->uval.lval.tail)
+
+#define ERL_VAR_LEN(x) ((x)->uval.vval.len)
+#define ERL_VAR_NAME(x) ((x)->uval.vval.name)
+#define ERL_VAR_VALUE(x) ((x)->uval.vval.v)
+
+#define ERL_CLOSURE_SIZE(x) ((x)->uval.funcval.size)
+#define ERL_FUN_CREATOR(x) ((x)->uval.funcval.creator)
+#define ERL_FUN_MODULE(x) ((x)->uval.funcval.module)
+#define ERL_FUN_UNIQ(x) ((x)->uval.funcval.uniq)
+#define ERL_FUN_INDEX(x) ((x)->uval.funcval.index)
+#define ERL_FUN_ARITY(x) ((x)->uval.funcval.arity)
+#define ERL_FUN_NEW_INDEX(x) ((x)->uval.funcval.new_index)
+#define ERL_FUN_MD5(x) ((x)->uval.funcval.md5)
+#define ERL_CLOSURE(x) ((x)->uval.funcval.closure)
+#define ERL_CLOSURE_ELEMENT(x,i) (ERL_CLOSURE(x)[(i)])
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* -------------------------------------------------------------------- */
+/* Type definitions of Erlang terms in C */
+/* -------------------------------------------------------------------- */
+
+typedef struct {
+ unsigned int count:24; /* reference counter */
+ unsigned int type:8; /* type of Erlang term */
+} Erl_Header;
+
+typedef struct {
+ Erl_Header h;
+ int i;
+} Erl_Integer;
+
+typedef struct {
+ Erl_Header h;
+ unsigned int u;
+} Erl_Uinteger;
+
+typedef struct {
+ Erl_Header h;
+ long long i;
+} Erl_LLInteger;
+
+typedef struct {
+ Erl_Header h;
+ unsigned long long u;
+} Erl_ULLInteger;
+
+typedef struct {
+ Erl_Header h;
+ double f;
+} Erl_Float;
+
+typedef struct {
+ Erl_Header h;
+ int len;
+ char *a;
+} Erl_Atom;
+
+typedef struct {
+ Erl_Header h;
+ char * node;
+ unsigned int number;
+ unsigned int serial;
+ unsigned char creation;
+} Erl_Pid;
+
+typedef struct {
+ Erl_Header h;
+ char * node;
+ unsigned int number;
+ unsigned char creation;
+} Erl_Port;
+
+typedef struct {
+ Erl_Header h;
+ char * node;
+ int len;
+ unsigned int n[3];
+ unsigned char creation;
+} Erl_Ref;
+
+typedef struct {
+ Erl_Header h;
+ int arity;
+ int is_neg;
+ unsigned short *digits;
+} Erl_Big;
+
+struct _eterm; /* forward */
+
+typedef struct {
+ Erl_Header h;
+ struct _eterm *head;
+ struct _eterm *tail;
+} Erl_List;
+
+typedef struct {
+ Erl_Header h;
+} Erl_EmptyList;
+
+typedef struct {
+ Erl_Header h;
+ int size;
+ struct _eterm **elems;
+} Erl_Tuple;
+
+typedef struct {
+ Erl_Header h;
+ int size;
+ unsigned char *b;
+} Erl_Binary;
+
+/* Variables may only exist in patterns.
+ * Note: identical variable names in a pattern
+ * denotes the same value.
+ */
+typedef struct {
+ Erl_Header h;
+ int len;
+ char *name;
+ struct _eterm *v;
+} Erl_Variable;
+
+
+typedef struct {
+ Erl_Header h;
+ int size; /* size of closure */
+ int arity; /* arity for new (post R7) external funs */
+ unsigned char md5[16]; /* md5 for new funs */
+ int new_index; /* new funs */
+ struct _eterm* creator; /* pid */
+ struct _eterm* module; /* module */
+ struct _eterm* index;
+ struct _eterm* uniq;
+ struct _eterm** closure;
+} Erl_Function;
+
+typedef struct _eterm {
+ union {
+ Erl_Integer ival;
+ Erl_Uinteger uival;
+ Erl_LLInteger llval;
+ Erl_ULLInteger ullval;
+ Erl_Float fval;
+ Erl_Atom aval;
+ Erl_Pid pidval;
+ Erl_Port portval;
+ Erl_Ref refval;
+ Erl_List lval;
+ Erl_EmptyList nval;
+ Erl_Tuple tval;
+ Erl_Binary bval;
+ Erl_Variable vval;
+ Erl_Function funcval;
+ Erl_Big bigval;
+ } uval;
+} ETERM;
+
+
+#define MAXREGLEN 255 /* max length of registered (atom) name */
+
+typedef struct {
+ int type; /* one of the message type constants in eiext.h */
+ ETERM *msg; /* the actual message */
+ ETERM *from;
+ ETERM *to;
+ char to_name[MAXREGLEN+1];
+} ErlMessage;
+
+typedef unsigned char Erl_Heap;
+
+
+/* -------------------------------------------------------------------- */
+/* The functions */
+/* -------------------------------------------------------------------- */
+
+void erl_init(void *x, long y);
+void erl_set_compat_rel(unsigned);
+int erl_connect_init(int, char*,short);
+int erl_connect_xinit(char*,char*,char*,struct in_addr*,char*,short);
+int erl_connect(char*);
+int erl_xconnect(struct in_addr*,char *);
+int erl_close_connection(int);
+int erl_receive(int, unsigned char*, int);
+int erl_receive_msg(int, unsigned char*, int, ErlMessage*);
+int erl_xreceive_msg(int, unsigned char**, int*, ErlMessage*);
+int erl_send(int, ETERM*, ETERM*);
+int erl_reg_send(int, char*, ETERM*);
+ETERM *erl_rpc(int,char*,char*,ETERM*);
+int erl_rpc_to(int,char*,char*,ETERM*);
+int erl_rpc_from(int,int,ErlMessage*);
+
+/* erl_publish returns open descriptor on success, or -1 */
+int erl_publish(int port);
+int erl_accept(int,ErlConnect*);
+
+const char *erl_thiscookie(void);
+const char *erl_thisnodename(void);
+const char *erl_thishostname(void);
+const char *erl_thisalivename(void);
+short erl_thiscreation(void);
+
+/* returns 0 on success, -1 if node not known to epmd or epmd not reached */
+int erl_unpublish(const char *alive);
+
+/* Report generic error to stderr. */
+void erl_err_msg(const char * __template, ...)
+ __attribute__ ((__format__ (printf, 1, 2)));
+/* Report generic error to stderr and die. */
+void erl_err_quit(const char * __template, ...)
+ __attribute__ ((__format__ (printf, 1, 2), __noreturn__));
+/* Report system/libc error to stderr. */
+void erl_err_ret(const char * __template, ...)
+ __attribute__ ((__format__ (printf, 1, 2)));
+/* Report system/libc error to stderr and die. */
+void erl_err_sys(const char * __template, ...)
+ __attribute__ ((__format__ (printf, 1, 2), __noreturn__));
+
+ETERM *erl_cons(ETERM*,ETERM*);
+ETERM *erl_copy_term(const ETERM*);
+ETERM *erl_element(int,const ETERM*);
+
+ETERM *erl_hd(const ETERM*);
+ETERM* erl_iolist_to_binary(const ETERM* term);
+char* erl_iolist_to_string(const ETERM* term);
+int erl_iolist_length(const ETERM*);
+int erl_length(const ETERM*);
+ETERM *erl_mk_atom(const char*);
+ETERM *erl_mk_binary(const char*,int);
+ETERM *erl_mk_empty_list(void);
+ETERM *erl_mk_estring(const char*, int);
+ETERM *erl_mk_float(double);
+ETERM *erl_mk_int(int);
+ETERM *erl_mk_longlong(long long);
+ETERM *erl_mk_list(ETERM**,int);
+ETERM *erl_mk_pid(const char*,unsigned int,unsigned int,unsigned char);
+ETERM *erl_mk_port(const char*,unsigned int,unsigned char);
+ETERM *erl_mk_ref(const char*,unsigned int,unsigned char);
+ETERM *erl_mk_long_ref(const char*,unsigned int,unsigned int,
+ unsigned int,unsigned char);
+ETERM *erl_mk_string(const char*);
+ETERM *erl_mk_tuple(ETERM**,int);
+ETERM *erl_mk_uint(unsigned int);
+ETERM *erl_mk_ulonglong(unsigned long long);
+ETERM *erl_mk_var(const char*);
+int erl_print_term(FILE*,const ETERM*);
+/* int erl_sprint_term(char*,const ETERM*); */
+int erl_size(const ETERM*);
+ETERM *erl_tl(const ETERM*);
+ETERM *erl_var_content(const ETERM*, const char*);
+
+ETERM *erl_format(char*, ... );
+int erl_match(ETERM*, ETERM*);
+
+char **erl_global_names(int fd, int *count);
+int erl_global_register(int fd, const char *name, ETERM *pid);
+int erl_global_unregister(int fd, const char *name);
+ETERM *erl_global_whereis(int fd, const char *name, char *node);
+
+void erl_init_malloc(Erl_Heap*,long);
+ETERM *erl_alloc_eterm(unsigned char);
+void erl_eterm_release(void);
+void erl_eterm_statistics(unsigned long*,unsigned long*);
+void erl_free_array(ETERM**,int);
+void erl_free_term(ETERM*);
+void erl_free_compound(ETERM*);
+void *erl_malloc(long);
+void erl_free(void*);
+
+int erl_compare_ext(unsigned char*, unsigned char*);
+ETERM *erl_decode(unsigned char*);
+ETERM *erl_decode_buf(unsigned char**);
+int erl_encode(ETERM*,unsigned char*t);
+int erl_encode_buf(ETERM*,unsigned char**);
+int erl_ext_size(unsigned char*);
+unsigned char erl_ext_type(unsigned char*); /* Note: returned 'char' before R9C */
+unsigned char *erl_peek_ext(unsigned char*,int);
+int erl_term_len(ETERM*);
+
+
+/* -------------------------------------------------------------------- */
+/* Wrappers around ei functions */
+/* -------------------------------------------------------------------- */
+
+/*
+ * Undocumented before R9C, included for compatibility with old code
+ */
+
+struct hostent *erl_gethostbyname(const char *name);
+struct hostent *erl_gethostbyaddr(const char *addr, int len, int type);
+struct hostent *erl_gethostbyname_r(const char *name,
+ struct hostent *hostp,
+ char *buffer,
+ int buflen,
+ int *h_errnop);
+struct hostent *erl_gethostbyaddr_r(const char *addr,
+ int length,
+ int type,
+ struct hostent *hostp,
+ char *buffer,
+ int buflen,
+ int *h_errnop);
+
+/*
+ * Undocumented, included for compatibility with old code
+ */
+
+void erl_init_resolve(void);
+int erl_distversion(int fd);
+int erl_epmd_connect(struct in_addr *inaddr);
+int erl_epmd_port(struct in_addr *inaddr, const char *alive, int *dist);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/erl_interface/info b/lib/erl_interface/info
new file mode 100644
index 0000000000..9612b0b6d4
--- /dev/null
+++ b/lib/erl_interface/info
@@ -0,0 +1,2 @@
+group: comm Interface and Communication Applications
+short: Low level interface to C
diff --git a/lib/erl_interface/priv/.gitignore b/lib/erl_interface/priv/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/erl_interface/priv/.gitignore
diff --git a/lib/erl_interface/src/INSTALL b/lib/erl_interface/src/INSTALL
new file mode 100644
index 0000000000..b42a17ac46
--- /dev/null
+++ b/lib/erl_interface/src/INSTALL
@@ -0,0 +1,182 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/lib/erl_interface/src/Makefile b/lib/erl_interface/src/Makefile
new file mode 100644
index 0000000000..5f0367bec1
--- /dev/null
+++ b/lib/erl_interface/src/Makefile
@@ -0,0 +1,31 @@
+#
+# %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%
+#
+
+# Invoke with GNU make or clearmake -C gnu.
+#
+
+# FIXME let configure put in this last part TARGET
+
+include $(ERL_TOP)/make/target.mk
+
+debug opt shared purify quantify purecov gcov:
+ $(MAKE) -f $(TARGET)/Makefile TYPE=$@
+
+clean depend docs release release_docs tests release_tests check:
+ $(MAKE) -f $(TARGET)/Makefile $@
diff --git a/lib/erl_interface/src/Makefile.in b/lib/erl_interface/src/Makefile.in
new file mode 100644
index 0000000000..b8ee5c83c7
--- /dev/null
+++ b/lib/erl_interface/src/Makefile.in
@@ -0,0 +1,903 @@
+#
+# %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%
+#
+
+###########################################################################
+##
+## This is a standalone make file for erl_interface. It is
+## to be preprocessed by the configure script and the result
+## is saved into the TARGER directory.
+##
+## We use 'vpath' to use plain C file names without the directory
+## part in dependency rules.
+##
+###########################################################################
+
+.PHONY : debug opt release clean distclean depend
+
+TARGET = @TARGET@
+
+# ----------------------------------------------------
+# Application version and release dir specification
+# ----------------------------------------------------
+include ../vsn.mk
+include $(TARGET)/eidefs.mk
+
+USING_MINGW=@MIXED_CYGWIN_MINGW@
+USING_VC=@MIXED_CYGWIN_VC@
+
+ifdef TESTROOT
+RELEASE_PATH=$(TESTROOT)
+else
+RELEASE_PATH=$(ERL_TOP)/release/$(TARGET)
+endif
+RELSYSDIR = $(RELEASE_PATH)/lib/erl_interface-$(EI_VSN)
+
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+ifeq ($(TYPE),debug)
+PURIFY =
+TYPEMARKER = .debug
+TYPE_FLAGS = -g -DDEBUG
+ifeq ($(TARGET),win32)
+LDFLAGS += -g
+endif
+else
+ifeq ($(TYPE),purify)
+PURIFY = purify
+TYPEMARKER = .purify
+TYPE_FLAGS = -DPURIFY -DNO_JUMP_TABLE
+else
+ifeq ($(TYPE),quantify)
+PURIFY = quantify
+TYPEMARKER = .quantify
+TYPE_FLAGS = -g -O2 -DQUANTIFY
+else
+ifeq ($(TYPE),purecov)
+PURIFY = purecov --follow-child-processes=yes
+TYPEMARKER = .purecov
+TYPE_FLAGS = -g -DPURECOV -DNO_JUMP_TABLE
+else
+ifeq ($(TYPE),gcov)
+PURIFY =
+TYPEMARKER =
+TYPE_FLAGS = -DNO_JUMP_TABLE -fprofile-arcs -ftest-coverage
+ifeq ($(TARGET),linux)
+LIBS += -lgcov
+endif
+else
+PURIFY =
+TYPEMARKER =
+TYPE_FLAGS =
+endif
+endif
+endif
+endif
+endif
+
+CC = @CC@
+LD = @LD@
+AR = @AR@
+RANLIB = @RANLIB@
+
+INCFLAGS = -I. -I../include -Iconnect -Iencode -Idecode -Imisc -Iepmd \
+ -Iregistry -I$(TARGET)
+
+ifeq ($(USING_VC),yes)
+WARNFLAGS = -Wall
+else
+WARNFLAGS = @WFLAGS@
+endif
+
+ifneq ($(findstring ose,$(TARGET)),ose)
+CFLAGS = @DED_CFLAGS@ $(WARNFLAGS) $(INCFLAGS) $(TYPE_FLAGS)
+else
+CFLAGS = @CFLAGS@ $(INCFLAGS)
+endif
+PROG_CFLAGS = @CFLAGS@ $(WARNFLAGS) $(INCFLAGS) $(TYPE_FLAGS) -Ilegacy
+
+ifeq ($(findstring vxworks,$(TARGET)),vxworks)
+PROG_CFLAGS += -nostartfiles -Wl,-r,-d
+endif
+
+
+INSTALL = @INSTALL@
+INSTALL_DIR = @INSTALL_DIR@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+
+# The default library (no extra extension in name) is for Unix with
+# thread support if exists. For windows MD is the default.
+#
+# ST = single threaded (Unix without thread support)
+# MT = multi threaded (on windows also static linking)
+# MD = multithreaded dynamic (default for cygwin cc wrapper)
+# MDD = multithreaded dynamic with debug symbols
+#
+ST_OBJDIR = $(ERL_TOP)/lib/erl_interface/obj.st$(TYPEMARKER)/$(TARGET)
+MT_OBJDIR = $(ERL_TOP)/lib/erl_interface/obj.mt$(TYPEMARKER)/$(TARGET)
+MD_OBJDIR = $(ERL_TOP)/lib/erl_interface/obj.md$(TYPEMARKER)/$(TARGET)
+MDD_OBJDIR = $(ERL_TOP)/lib/erl_interface/obj.mdd$(TYPEMARKER)/$(TARGET)
+OBJDIR = $(ERL_TOP)/lib/erl_interface/obj$(TYPEMARKER)/$(TARGET)
+BINDIR = $(ERL_TOP)/lib/erl_interface/bin/$(TARGET)
+
+# FIXME maybe use this opt and remove (int) cast to is*() functions
+# -Wno-char-subscripts
+# -Wshadow
+
+vpath %.c connect:encode:decode:misc:epmd:legacy:registry
+
+
+###########################################################################
+# List targets
+###########################################################################
+
+ifeq ($(TARGET),win32)
+EXE=.exe
+else
+EXE=
+endif
+
+ifeq ($(USING_VC),yes)
+LIBEXT=.lib
+LIBPRE=
+MTFLAG=-MT
+
+else
+LIBEXT=.a
+LIBPRE=lib
+MTFLAG=
+
+endif
+
+###########################################################################
+# Specify targets names
+###########################################################################
+
+ERL_CALL = $(BINDIR)/erl_call$(EXE)
+
+ifdef THR_DEFS
+ST_EILIB = $(OBJDIR)/$(LIBPRE)ei_st$(LIBEXT)
+ST_ERLLIB = $(OBJDIR)/$(LIBPRE)erl_interface_st$(LIBEXT)
+MT_EILIB = $(OBJDIR)/$(LIBPRE)ei$(LIBEXT)
+MT_ERLLIB = $(OBJDIR)/$(LIBPRE)erl_interface$(LIBEXT)
+else
+ST_EILIB = $(OBJDIR)/$(LIBPRE)ei$(LIBEXT)
+ST_ERLLIB = $(OBJDIR)/$(LIBPRE)erl_interface$(LIBEXT)
+endif
+MD_EILIB = $(OBJDIR)/$(LIBPRE)ei_md$(LIBEXT)
+MDD_EILIB = $(OBJDIR)/$(LIBPRE)ei_mdd$(LIBEXT)
+MD_ERLLIB = $(OBJDIR)/$(LIBPRE)erl_interface_md$(LIBEXT)
+MDD_ERLLIB = $(OBJDIR)/$(LIBPRE)erl_interface_mdd$(LIBEXT)
+
+###########################################################################
+# Specify targets to build
+###########################################################################
+
+ifneq ($(findstring ose,$(TARGET)),ose)
+EXE_TARGETS = \
+ $(ERL_CALL)
+else
+EXE_TARGETS =
+endif
+
+ifeq ($(USING_VC),yes)
+
+# Windows targets
+
+TARGETS = \
+ $(BINDIR) \
+ $(OBJDIR) \
+ $(MT_OBJDIR) \
+ $(MD_OBJDIR) \
+ $(MDD_OBJDIR) \
+ $(OBJ_TARGETS) \
+ $(EXE_TARGETS)
+
+OBJ_TARGETS = \
+ $(MT_EILIB) \
+ $(MD_EILIB) \
+ $(MDD_EILIB) \
+ $(MT_ERLLIB) \
+ $(MD_ERLLIB) \
+ $(MDD_ERLLIB)
+
+FAKE_TARGETS = \
+ $(OBJDIR)/erl_fake_prog_mt$(EXE) \
+ $(OBJDIR)/ei_fake_prog_mt$(EXE) \
+ $(OBJDIR)/erl_fake_prog_mt_cxx$(EXE) \
+ $(OBJDIR)/ei_fake_prog_mt_cxx$(EXE) \
+ $(OBJDIR)/erl_fake_prog_md$(EXE) \
+ $(OBJDIR)/ei_fake_prog_md$(EXE) \
+ $(OBJDIR)/erl_fake_prog_cxx_md$(EXE) \
+ $(OBJDIR)/ei_fake_prog_cxx_md$(EXE) \
+ $(OBJDIR)/erl_fake_prog_mdd$(EXE) \
+ $(OBJDIR)/ei_fake_prog_mdd$(EXE) \
+ $(OBJDIR)/erl_fake_prog_cxx_mdd$(EXE) \
+ $(OBJDIR)/ei_fake_prog_cxx_mdd$(EXE) \
+
+else
+
+ifeq ($USING_MINGW,yes)
+TARGETS = \
+ $(BINDIR) \
+ $(OBJDIR) \
+ $(MD_OBJDIR) \
+ $(OBJ_TARGETS) \
+ $(EXE_TARGETS)
+
+OBJ_TARGETS = \
+ $(MD_EILIB) \
+ $(MD_ERLLIB)
+
+FAKE_TARGETS = \
+ $(OBJDIR)/erl_fake_prog_md$(EXE) \
+ $(OBJDIR)/ei_fake_prog_md$(EXE) \
+ $(OBJDIR)/erl_fake_prog_cxx_md$(EXE) \
+ $(OBJDIR)/ei_fake_prog_cxx_md$(EXE)
+else
+# Unix targets
+
+ifdef THR_DEFS
+
+TARGETS = \
+ $(BINDIR) \
+ $(OBJDIR) \
+ $(ST_OBJDIR) \
+ $(MT_OBJDIR) \
+ $(OBJ_TARGETS) \
+ $(EXE_TARGETS)
+
+OBJ_TARGETS = \
+ $(ST_EILIB) \
+ $(ST_ERLLIB) \
+ $(MT_EILIB) \
+ $(MT_ERLLIB)
+
+FAKE_TARGETS = \
+ $(ST_OBJDIR)/erl_fake_prog_st$(EXE) \
+ $(ST_OBJDIR)/ei_fake_prog_st$(EXE) \
+ $(ST_OBJDIR)/erl_fake_prog_cxx_st$(EXE) \
+ $(ST_OBJDIR)/ei_fake_prog_cxx_st$(EXE) \
+ $(MT_OBJDIR)/erl_fake_prog_mt$(EXE) \
+ $(MT_OBJDIR)/ei_fake_prog_mt$(EXE) \
+ $(MT_OBJDIR)/erl_fake_prog_mt_cxx$(EXE) \
+ $(MT_OBJDIR)/ei_fake_prog_mt_cxx$(EXE)
+
+else
+
+TARGETS = \
+ $(BINDIR) \
+ $(OBJDIR) \
+ $(ST_OBJDIR) \
+ $(OBJ_TARGETS) \
+ $(EXE_TARGETS)
+
+OBJ_TARGETS = \
+ $(ST_EILIB) \
+ $(ST_ERLLIB)
+
+FAKE_TARGETS = \
+ $(ST_OBJDIR)/erl_fake_prog_st$(EXE) \
+ $(ST_OBJDIR)/ei_fake_prog_st$(EXE) \
+ $(ST_OBJDIR)/erl_fake_prog_cxx_st$(EXE) \
+ $(ST_OBJDIR)/ei_fake_prog_cxx_st$(EXE)
+
+endif
+
+endif
+
+endif
+###########################################################################
+# List all source files
+###########################################################################
+
+# FIXME do we need dummy here for XX.h that was needed before??
+
+HEADERS = \
+ ../include/ei.h \
+ ../include/ei_connect.h \
+ ../include/eicode.h \
+ ../include/erl_interface.h
+
+EISOURCES = \
+ $(CONNECTSRC) \
+ $(DECODESRC) \
+ $(ENCODESRC) \
+ $(EPMDSRC) \
+ $(MISCSRC) \
+ $(REGISTRYSRC)
+
+CONNECTSRC = \
+ connect/ei_connect.c \
+ connect/ei_resolve.c \
+ connect/eirecv.c \
+ connect/send.c \
+ connect/send_exit.c \
+ connect/send_reg.c
+
+DECODESRC = \
+ decode/decode_atom.c \
+ decode/decode_big.c \
+ decode/decode_bignum.c \
+ decode/decode_binary.c \
+ decode/decode_boolean.c \
+ decode/decode_char.c \
+ decode/decode_double.c \
+ decode/decode_fun.c \
+ decode/decode_intlist.c \
+ decode/decode_list_header.c \
+ decode/decode_long.c \
+ decode/decode_pid.c \
+ decode/decode_port.c \
+ decode/decode_ref.c \
+ decode/decode_skip.c \
+ decode/decode_string.c \
+ decode/decode_trace.c \
+ decode/decode_tuple_header.c \
+ decode/decode_ulong.c \
+ decode/decode_version.c \
+ $(DECODESRC_LONGLONG)
+
+ifneq ($(findstring vxworks,$(TARGET)),vxworks)
+DECODESRC_LONGLONG = \
+ decode/decode_longlong.c \
+ decode/decode_ulonglong.c
+else
+DECODESRC_LONGLONG =
+endif
+
+
+ENCODESRC = \
+ encode/encode_atom.c \
+ encode/encode_big.c \
+ encode/encode_bignum.c \
+ encode/encode_binary.c \
+ encode/encode_boolean.c \
+ encode/encode_char.c \
+ encode/encode_double.c \
+ encode/encode_fun.c \
+ encode/encode_list_header.c \
+ encode/encode_long.c \
+ encode/encode_pid.c \
+ encode/encode_port.c \
+ encode/encode_ref.c \
+ encode/encode_string.c \
+ encode/encode_trace.c \
+ encode/encode_tuple_header.c \
+ encode/encode_ulong.c \
+ encode/encode_version.c \
+ $(ENCODESRC_LONGLONG)
+
+ifneq ($(findstring vxworks,$(TARGET)),vxworks)
+ENCODESRC_LONGLONG = \
+ encode/encode_longlong.c \
+ encode/encode_ulonglong.c
+else
+ENCODESRC_LONGLONG =
+endif
+
+
+EPMDSRC = \
+ epmd/epmd_port.c \
+ epmd/epmd_publish.c \
+ epmd/epmd_unpublish.c
+
+MISCSRC = \
+ misc/ei_decode_term.c \
+ misc/ei_format.c \
+ misc/ei_locking.c \
+ misc/ei_malloc.c \
+ misc/ei_portio.c \
+ misc/ei_printterm.c \
+ misc/ei_pthreads.c \
+ misc/ei_trace.c \
+ misc/ei_x_encode.c \
+ misc/eimd5.c \
+ misc/get_type.c \
+ misc/show_msg.c \
+ misc/ei_compat.c
+
+REGISTRYSRC = \
+ registry/hash_dohash.c \
+ registry/hash_foreach.c \
+ registry/hash_freetab.c \
+ registry/hash_insert.c \
+ registry/hash_isprime.c \
+ registry/hash_lookup.c \
+ registry/hash_newtab.c \
+ registry/hash_remove.c \
+ registry/hash_resize.c \
+ registry/hash_rlookup.c \
+ registry/reg_close.c \
+ registry/reg_delete.c \
+ registry/reg_dirty.c \
+ registry/reg_dump.c \
+ registry/reg_free.c \
+ registry/reg_get.c \
+ registry/reg_getf.c \
+ registry/reg_geti.c \
+ registry/reg_getp.c \
+ registry/reg_gets.c \
+ registry/reg_make.c \
+ registry/reg_open.c \
+ registry/reg_purge.c \
+ registry/reg_resize.c \
+ registry/reg_restore.c \
+ registry/reg_set.c \
+ registry/reg_setf.c \
+ registry/reg_seti.c \
+ registry/reg_setp.c \
+ registry/reg_sets.c \
+ registry/reg_stat.c \
+ registry/reg_tabstat.c
+
+ERLSOURCES = \
+ legacy/decode_term.c \
+ legacy/encode_term.c \
+ legacy/erl_connect.c \
+ legacy/erl_error.c \
+ legacy/erl_eterm.c \
+ legacy/erl_fix_alloc.c \
+ legacy/erl_format.c \
+ legacy/erl_malloc.c \
+ legacy/erl_marshal.c \
+ legacy/erl_resolve.c \
+ legacy/erl_timeout.c \
+ legacy/global_names.c \
+ legacy/global_register.c \
+ legacy/global_unregister.c \
+ legacy/global_whereis.c
+
+SOURCES = $(EISOURCES) $(ERLSOURCES)
+
+OSE_EISOURCES = \
+ $(DECODESRC) \
+ $(ENCODESRC) \
+ misc/ei_decode_term.c \
+ misc/ei_format.c \
+ misc/ei_locking.c \
+ misc/ei_malloc.c \
+ misc/ei_printterm.c \
+ misc/ei_pthreads.c \
+ misc/ei_trace.c \
+ misc/ei_x_encode.c \
+ misc/eimd5.c \
+ misc/get_type.c \
+ misc/show_msg.c \
+ misc/ei_compat.c \
+ registry/hash_dohash.c \
+ registry/hash_foreach.c \
+ registry/hash_freetab.c \
+ registry/hash_insert.c \
+ registry/hash_isprime.c \
+ registry/hash_lookup.c \
+ registry/hash_newtab.c \
+ registry/hash_remove.c \
+ registry/hash_resize.c \
+ registry/hash_rlookup.c
+
+OSE_ERLSOURCES = \
+ legacy/decode_term.c \
+ legacy/encode_term.c \
+ legacy/erl_error.c \
+ legacy/erl_eterm.c \
+ legacy/erl_fix_alloc.c \
+ legacy/erl_format.c \
+ legacy/erl_malloc.c \
+ legacy/erl_marshal.c
+
+OSE_SOURCES = $(OSE_EISOURCES) $(OSE_ERLSOURCES)
+
+NEVERUSED = \
+ whereis.c \
+ ei_send.c \
+ ei_send_reg.c \
+ send_link.c
+
+ERLCALL = \
+ prog/erl_call.c \
+ prog/erl_start.c
+
+
+# Note that encode/decode_term.c defines ei functions that is
+# located in the erl_interface library, not ei library.
+
+ifneq ($(findstring ose,$(TARGET)),ose)
+ST_EIOBJECTS = $(addprefix $(ST_OBJDIR)/,$(notdir $(EISOURCES:.c=.o)))
+ST_ERLOBJECTS = $(addprefix $(ST_OBJDIR)/,$(notdir $(ERLSOURCES:.c=.o)))
+else
+ST_EIOBJECTS = $(addprefix $(ST_OBJDIR)/,$(notdir $(OSE_EISOURCES:.c=.o)))
+ST_ERLOBJECTS = $(addprefix $(ST_OBJDIR)/,$(notdir $(OSE_ERLSOURCES:.c=.o)))
+endif
+MT_EIOBJECTS = $(addprefix $(MT_OBJDIR)/,$(notdir $(EISOURCES:.c=.o)))
+MT_ERLOBJECTS = $(addprefix $(MT_OBJDIR)/,$(notdir $(ERLSOURCES:.c=.o)))
+MD_EIOBJECTS = $(addprefix $(MD_OBJDIR)/,$(notdir $(EISOURCES:.c=.o)))
+MD_ERLOBJECTS = $(addprefix $(MD_OBJDIR)/,$(notdir $(ERLSOURCES:.c=.o)))
+MDD_EIOBJECTS = $(addprefix $(MDD_OBJDIR)/,$(notdir $(EISOURCES:.c=.o)))
+MDD_ERLOBJECTS = $(addprefix $(MDD_OBJDIR)/,$(notdir $(ERLSOURCES:.c=.o)))
+
+###########################################################################
+# Main targets
+###########################################################################
+
+# FIXME this assumes execution order
+# FIXME move up and add exe prefix if needed....
+
+debug opt: $(TARGETS)
+
+docs:
+
+tests:
+
+clean:
+ rm -f $(ST_EIOBJECTS) $(ST_ERLOBJECTS) $(ST_EILIB) $(ST_ERLLIB)
+ rm -f $(MT_EIOBJECTS) $(MT_ERLOBJECTS) $(MT_EILIB) $(MT_ERLLIB)
+ rm -f $(MD_EIOBJECTS) $(MD_ERLOBJECTS) $(MD_EILIB) $(MD_ERLLIB)
+ rm -f $(MDD_EIOBJECTS) $(MDD_ERLOBJECTS) $(MDD_EILIB) $(MDD_ERLLIB)
+ rm -f $(ERL_CALL)
+ rm -f $(FAKE_TARGETS)
+
+distclean: clean
+ rm -f config.h config.log config.status configure
+
+
+###########################################################################
+# FIXME move this VxWorks stuff to configure or something
+###########################################################################
+
+# FIXME depend on $(TARGET)/Makefile ???
+
+ifeq ($(findstring vxworks,$(TARGET)),vxworks)
+$(TARGET)/config.h:
+ echo "/* Generated by Makefile */" > $@
+ echo "#define HAVE_STRERROR 1" >> $@
+endif
+
+ifeq ($(findstring ose,$(TARGET)),ose)
+$(TARGET)/config.h:
+ echo "/* Generated by Makefile */" > $@
+ echo "#define HAVE_STRERROR 1" >> $@
+endif
+
+###########################################################################
+# Default rules, normal and threaded
+###########################################################################
+
+$(ST_OBJDIR)/%.o: %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+$(MT_OBJDIR)/%.o: %.c
+ $(CC) $(MTFLAG) $(CFLAGS) $(THR_DEFS) -c $< -o $@
+
+$(MD_OBJDIR)/%.o: %.c
+ $(CC) -MD $(CFLAGS) $(THR_DEFS) -c $< -o $@
+
+$(MD_OBJDIR)/%.o: %.c
+ $(CC) -MD $(CFLAGS) $(THR_DEFS) -c $< -o $@
+
+$(MDD_OBJDIR)/%.o: %.c
+ $(CC) -MDd $(CFLAGS) $(THR_DEFS) -c $< -o $@
+
+###########################################################################
+# Create directories
+###########################################################################
+
+$(BINDIR):
+ mkdir -p $(BINDIR)
+
+$(OBJDIR):
+ mkdir -p $(OBJDIR)
+
+$(ST_OBJDIR):
+ mkdir -p $(ST_OBJDIR)
+
+$(MT_OBJDIR):
+ mkdir -p $(MT_OBJDIR)
+
+$(MD_OBJDIR):
+ mkdir -p $(MD_OBJDIR)
+
+$(MDD_OBJDIR):
+ mkdir -p $(MDD_OBJDIR)
+
+###########################################################################
+# Special rules
+###########################################################################
+
+ifeq ($(TARGET),win32)
+
+# Windows archive creation
+
+$(ST_EILIB) : $(ST_EIOBJECTS)
+ $(AR) -out:$@ $(ST_EIOBJECTS)
+ $(RANLIB) $@
+
+$(ST_ERLLIB) : $(ST_ERLOBJECTS)
+ $(AR) -out:$@ $(ST_ERLOBJECTS)
+ $(RANLIB) $@
+
+$(MT_EILIB) : $(MT_EIOBJECTS)
+ $(AR) -out:$@ $(MT_EIOBJECTS)
+ $(RANLIB) $@
+
+$(MT_ERLLIB) : $(MT_ERLOBJECTS)
+ $(AR) -out:$@ $(MT_ERLOBJECTS)
+ $(RANLIB) $@
+
+$(MD_EILIB) : $(MD_EIOBJECTS)
+ $(AR) -out:$@ $(MD_EIOBJECTS)
+ $(RANLIB) $@
+
+$(MD_ERLLIB) : $(MD_ERLOBJECTS)
+ $(AR) -out:$@ $(MD_ERLOBJECTS)
+ $(RANLIB) $@
+
+$(MDD_EILIB) : $(MDD_EIOBJECTS)
+ $(AR) -out:$@ $(MDD_EIOBJECTS)
+ $(RANLIB) $@
+
+$(MDD_ERLLIB) : $(MDD_ERLOBJECTS)
+ $(AR) -out:$@ $(MDD_ERLOBJECTS)
+ $(RANLIB) $@
+
+else
+
+# Unix archive creation
+
+$(ST_EILIB) : $(ST_EIOBJECTS)
+ rm -f $@
+ $(AR) rcv $@ $(ST_EIOBJECTS)
+ifdef RANLIB
+ $(RANLIB) $@
+endif
+
+$(ST_ERLLIB) : $(ST_ERLOBJECTS)
+ rm -f $@
+ $(AR) rcv $@ $(ST_ERLOBJECTS)
+ifdef RANLIB
+ $(RANLIB) $@
+endif
+
+$(MT_EILIB) : $(MT_EIOBJECTS)
+ rm -f $@
+ $(AR) rcv $@ $(MT_EIOBJECTS)
+ifdef RANLIB
+ $(RANLIB) $@
+endif
+
+$(MT_ERLLIB) : $(MT_ERLOBJECTS)
+ rm -f $@
+ $(AR) rcv $@ $(MT_ERLOBJECTS)
+ifdef RANLIB
+ $(RANLIB) $@
+endif
+
+endif
+
+###########################################################################
+# erl_call FIXME how to avoid explicit -lsocket on winows???
+###########################################################################
+
+ifeq ($(TARGET),win32)
+$(ERL_CALL): $(ERLCALL) ../include/ei.h $(MD_EILIB)
+ $(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)
+
+$(ST_OBJDIR)/erl_call.o: prog/erl_call.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+$(ST_OBJDIR)/erl_start.o: prog/erl_start.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+else
+ifeq ($(findstring ose,$(TARGET)),ose)
+$(ERL_CALL):
+else
+ifdef THR_DEFS
+$(ERL_CALL): $(ERLCALL) ../include/ei.h $(MT_EILIB)
+ $(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) \
+ -L$(OBJDIR) -lei $(LIBS)
+endif
+endif
+endif
+endif
+
+###########################################################################
+# Fake application targets used to test header files and linking
+###########################################################################
+
+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 \
+ $(LIBS)
+
+$(ST_OBJDIR)/ei_fake_prog_st$(EXE): prog/ei_fake_prog.c $(ST_EILIB)
+ $(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) \
+ -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)
+
+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 \
+ $(LIBS)
+
+$(ST_OBJDIR)/ei_fake_prog_st$(EXE): prog/ei_fake_prog.c $(ST_EILIB)
+ $(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) \
+ -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)
+
+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) \
+ -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 $@ $< \
+ -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++ $< \
+ -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++ $< \
+ -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) \
+ -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 $@ $< \
+ -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++ $< \
+ -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++ $< \
+ -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) \
+ -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 $@ $< \
+ -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++ $< \
+ -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++ $< \
+ -L$(OBJDIR) -lei_r $(THR_LIBS) $(LIBS)
+
+###########################################################################
+# Create dependency file using gcc -MM
+###########################################################################
+
+depend:
+ @echo "Generating dependency file depend.mk..."
+ @echo "# Generated dependency rules" > depend.mk; \
+ $(CC) $(CFLAGS) -MM $(SOURCES) | \
+ sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
+ sed 's/^.*:/\$$\(ST_OBJDIR\)\/&/' >> depend.mk; \
+ echo >> depend.mk; \
+ $(CC) $(CFLAGS) -MM $(SOURCES) | \
+ sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
+ sed 's/^.*:/\$$\(MT_OBJDIR\)\/&/' >> depend.mk; \
+ echo >> depend.mk; \
+ $(CC) $(CFLAGS) -MM $(SOURCES) | \
+ sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
+ sed 's/^.*:/\$$\(MD_OBJDIR\)\/&/' >> depend.mk; \
+ echo >> depend.mk; \
+ $(CC) $(CFLAGS) -MM $(SOURCES) | \
+ sed 's&$(TARGET)&\$$\(TARGET\)&g' | \
+ sed 's/^.*:/\$$\(MDD_OBJDIR\)\/&/' >> depend.mk; \
+ echo >> depend.mk
+
+# For some reason this has to be after 'opt' target
+include depend.mk
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+
+EXTRA = \
+ INSTALL \
+ Makefile \
+ Makefile.in \
+ README \
+ README.internal \
+ $(TARGET)/eidefs.mk
+
+release: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/include
+ $(INSTALL_DIR) $(RELSYSDIR)/lib
+ $(INSTALL_DIR) $(RELSYSDIR)/bin
+ $(INSTALL_DIR) $(RELSYSDIR)/src/auxdir
+ $(INSTALL_DIR) $(RELSYSDIR)/src/connect
+ $(INSTALL_DIR) $(RELSYSDIR)/src/decode
+ $(INSTALL_DIR) $(RELSYSDIR)/src/encode
+ $(INSTALL_DIR) $(RELSYSDIR)/src/epmd
+ $(INSTALL_DIR) $(RELSYSDIR)/src/legacy
+ $(INSTALL_DIR) $(RELSYSDIR)/src/misc
+ $(INSTALL_DIR) $(RELSYSDIR)/src/prog
+ $(INSTALL_DIR) $(RELSYSDIR)/src/registry
+ $(INSTALL_DATA) $(HEADERS) $(RELSYSDIR)/include
+ $(INSTALL_DATA) $(OBJ_TARGETS) $(RELSYSDIR)/lib
+ifneq ($(EXE_TARGETS),)
+ $(INSTALL_PROGRAM) $(EXE_TARGETS) $(RELSYSDIR)/bin
+endif
+ $(INSTALL_DATA) $(EXTRA) $(RELSYSDIR)/src
+ $(INSTALL_DATA) connect/*.[ch] $(RELSYSDIR)/src/connect
+ $(INSTALL_DATA) decode/*.[ch] $(RELSYSDIR)/src/decode
+ $(INSTALL_DATA) encode/*.[ch] $(RELSYSDIR)/src/encode
+ $(INSTALL_DATA) epmd/*.[ch] $(RELSYSDIR)/src/epmd
+ $(INSTALL_DATA) misc/*.[ch] $(RELSYSDIR)/src/misc
+ $(INSTALL_DATA) registry/*.[ch] $(RELSYSDIR)/src/registry
+ $(INSTALL_DATA) legacy/*.[ch] $(RELSYSDIR)/src/legacy
+ $(INSTALL_DATA) prog/*.[ch] $(RELSYSDIR)/src/prog
+
+release_docs:
+
+release_tests:
diff --git a/lib/erl_interface/src/README b/lib/erl_interface/src/README
new file mode 100644
index 0000000000..feee2e48e8
--- /dev/null
+++ b/lib/erl_interface/src/README
@@ -0,0 +1,186 @@
+Erl_interface README July 2, 1997.
+Bjorn Gustavsson
+----------------------------------
+
+About the erl_interface library
+-------------------------------
+
+The pre-release version of erl_interface provided in this package
+is compiled for use of DNS and with symbol information.
+Also, assertions are enabled, meaning that the code will be a
+little bit slower. In the final release, there will be two
+alternative libraries shipped, with and without assertions.
+
+If an assertion triggers, there will be a printout similiar to this
+one:
+
+ Assertion failed: ep != NULL in erl_eterm.c, line 694
+ Abort (core dumped)
+
+The cause of an assertion can be either errors in the application
+program (for instance, passing NULL pointers to any function that
+expects an ETERM pointer) or in erl_interface itself.
+
+If you encounter any assertion failures which think you originate in
+erl_interface, I'll need the following information to track it down:
+
+1a) The printout from the assertion, especially filename and line number.
+
+1b) A dump of the stack, obtained by running a debugger.
+
+ - OR -
+
+2) The source for a small test program which triggers the assertion.
+
+Changes in this version
+-----------------------
+
+There is now *one* representation for an empty list, not two as is used
+to be. An empty list is represented by the Erl_EmptyList structure.
+There are new macros, ERL_IS_EMPTY_LIST(ep), to test for an empty list,
+and ERL_IS_CONS(ep) to test for a cons cell (more on that below).
+
+None of the type checking macros (ERL_IS_LIST(ep), ERL_IS_TUPLE(ep), etc),
+accept NULL pointers any longer. Make sure to only pass valid ETERM
+pointers.
+
+erl_cons(head, tail) now requires tail to be a non-NULL pointer.
+To represent the end of a list, use the return value from
+erl_mk_empty_list().
+
+erl_length() now only works for a proper list; i.e. for the
+the term [a|b], erl_length() returns -1.
+
+erl_tl(), erl_hd() is now silent if given a bad list
+(but still returns NULL).
+
+The string data type has been removed, including the macro ERL_IS_STRING().
+The functions erl_mk_string() and erl_mk_estring() still exists, but builds
+lists instead of strings.
+
+There are two new functions to convert I/O lists (= deep lists of
+byte-sized integers and binaries):
+
+ char* erl_iolist_to_string(ETERM* term);
+ ETERM* erl_iolist_to_binary(ETERM* term);
+
+The erl_iolist_to_string() function converts an I/O list to a
+'\0' terminated string.
+
+Known bugs
+----------
+
+The term erl_mk_small_int(-0x10000000) will be incorrectly represented
+if decoded and sent to the Erlang side.
+
+Calling erl_mk_int() on an integer whose value is represented
+in more than 28 bits, will result in an ETERM which is not an integer
+(i.e. ERL_IS_INTEGER() will fail).
+
+Planned future changes
+----------------------
+
+Support for heap allocation of Erlang terms will be dropped.
+It will be assumed that malloc()/free() functions are available.
+
+There will be one header file, erl_interface.h, not one for each
+"module".
+
+The type checking macros for lists
+----------------------------------
+
+In this version of erl_interface, there are three macros for testing
+types of lists:
+
+ERL_IS_LIST(term)
+ERL_IS_CONS(term)
+ERL_IS_EMPTY_LIST(term)
+
+They behave as follows:
+
+ERL_IS_LIST(term) is used like a list/1 guard function in Erlang:
+
+function(List) when list(List) ->
+ ....
+
+It is true if its argument is a list, even an empty list.
+
+ERL_IS_EMPTY(term) is true only for an empty list; thus it can be
+used like the following function head:
+
+function([]) ->
+ ....
+
+ERL_IS_CONS(term) only if the list is not empty; it is similar to the
+following function head:
+
+function([H|T] ->
+ ....
+
+Documentation for new functions
+-------------------------------
+
+/***********************************************************************
+ * I o l i s t f u n c t i o n s
+ *
+ * The following functions handles I/O lists.
+ *
+ * Informally, an I/O list is a deep list of characters and binaries,
+ * which can be sent to an Erlang port.
+ *
+ * Formally, in BNF, an I/O list is defined as:
+ *
+ * iolist ::= []
+ * | Binary
+ * | [iohead | iolist]
+ * ;
+ *
+ * iohead ::= Binary
+ * | Byte (integer in the range [0..255])
+ * | iolist
+ * ;
+ *
+ * Note that versions of Erlang/OTP prior to R2 had a slightly more
+ * restricted definition of I/O lists, in that the tail of a an I/O list
+ * was not allowed to be a binary. The erl_interface functions
+ * for I/O lists follows the more liberal rules described by the BNF
+ * description above.
+ ***********************************************************************/
+
+/*
+ * This function converts an I/O list to a '\0' terminated C string.
+ * The I/O list must not contain any occurrences of the integer 0.
+ *
+ * The string will be in memory allocated by erl_malloc(). It is the
+ * responsibility of the caller to eventually call erl_free() to free
+ * the memory.
+ *
+ * Returns: NULL if the list was not an I/O list or contained
+ * the integer 0, otherwise a pointer to '\0' terminated string.
+ */
+
+char*
+erl_iolist_to_string(term)
+ ETERM* term; /* Term to convert to a string. */
+
+/*
+ * This function converts an I/O list to a binary term.
+ *
+ * Returns: NULL if the list was not an I/O list, otherwise
+ * an ETERM pointer pointing to a binary term.
+ */
+
+ETERM*
+erl_iolist_to_binary(term)
+ ETERM* term; /* Term to convert to a binary. */
+
+/*
+ * Returns the length of an I/O list.
+ *
+ * Returns: -1 if the term if the given term is not a I/O list,
+ * or the length otherwise.
+ */
+
+int
+erl_iolist_length(term)
+ ETERM* term;
diff --git a/lib/erl_interface/src/README.internal b/lib/erl_interface/src/README.internal
new file mode 100644
index 0000000000..c1f2d6863f
--- /dev/null
+++ b/lib/erl_interface/src/README.internal
@@ -0,0 +1,285 @@
+******************************************************************************
+ General
+******************************************************************************
+
+There are two different interfaces, the old 'erl_interface' and 'ei'.
+The old interface is to depend on the new one, not the other way arount.
+
+Erl_interface should be "thread safe", i.e. you should be able to
+handle connections, convert data etc from different threads.
+
+Ei should be "reentrant" or "async safe", i.e. no locks should be set
+so that if an ei function is called inside an signal handler there
+could be a deadlock.
+
+VxWorks call the operating processes "tasks". These are to be handled the
+same way as Unix threads, i.e. there can only be one C node for all tasks
+using the old interface.
+
+Try to keep the documented functions, variables and symbols in sync
+between
+
+ * Documentation
+
+ * ei.h and erl_interface.h
+
+ * prog/ei_fake_prog.c and prog/erl_fake_prog.c
+
+From time to time do a
+
+ % (cd src; gmake check)
+
+(FIXME this check should be rewritten to a test case)
+
+
+******************************************************************************
+ Directories
+******************************************************************************
+
+ * src/aux/
+
+ Support files for configure described in the next section
+
+ * src/legacy/
+
+ Old erl_interface stuff FIXME what about thread support etc....?
+
+ * src/connect/
+
+ Create nodes, connections, communication with the other node etc
+
+ * src/decode/
+
+ Simple decode functions
+
+ * src/encode/
+
+ Simple encode functions
+
+ * src/epmd/
+
+ Handle communication with epmd
+
+ * src/registry/
+
+ Key/value database with optional mnesia back up
+
+ * src/misc/
+
+ The rest of the library
+
+ * src/prog/
+
+ erl_call and some test programs for compiling and linking
+
+ * src/not_used/
+
+ Strange, some files are not used....
+
+
+******************************************************************************
+ Configuration support files
+******************************************************************************
+
+The build uses GNU configure and libtool. The libtool and autoconf
+package don't need to be installed to configure and build the
+sources. But in "maintainer mode" you need them to update some files
+in the source distribution.
+
+ * configure.in
+
+ Used in maintainer mode together with "aclocal.m4" to create
+ "configure". "configure.in" is hand written and only need to
+ be updated when you change the sources to use new header files
+ or C compiler features. You may get some hints about what to
+ update using a recent autoconf package and do
+
+ % cd erl_inteface
+ % autoscan src
+
+ The result to compare with the current "configure.in" will be
+ stored in "src/configure.scan".
+
+ * aclocal.m4
+
+ This file contains macros generated by ??? appended
+ with the content of "libtool.m4" in the installed libtool
+ package. (FIXME don't know when this is to be updated and
+ why it contains so much).
+
+ * src/aux/config.guess
+ * src/aux/config.sub
+
+ Used by "configure" to form the subdirectory name
+ "cpu-vendor-os".
+
+ * src/aux/install-sh*
+
+ Used if no other BSD compatible install script is found.
+
+ * src/aux/config.h.in
+
+ Used by "configure" as a template for the resulting
+ "src/config.h". The file "config.h.in" should be
+ updated when "configure.in" is updated because the
+ new macros used in your source and this is the file
+ where they are listed. You can find out what to update
+ using
+
+ % autoheader
+
+ * ltmain.sh
+
+ This is XXX (FIXME what?)
+
+The base for the configure.in script was created with 'autoscan'.
+The base for the config.h.in file was created with 'autoheader'.
+
+
+******************************************************************************
+ Writing source
+******************************************************************************
+
+C files in "registry" are considered users of 'ei' and should not
+include "eidef.h" or "config.h", only "ei.h".
+
+C files in "prog" could include "config.h" directly.
+
+Other C files should include "eidef.h" as the first line of
+source. "eidef.h" contains some common constants and macros and
+also includes config.h.
+
+In general avoid including other header files from header files.
+The exception is to make the protoypes complete to the user of
+this library, i.e. to include <stdio.h> to defined FILE or
+to include "ei_x_encode" to define the type ei_x_buff.
+
+The function ei_decode_term() (FIXME encode_term?) work on ETERM,
+i.e. it converts between the old erl_interface format and ei.
+Because of this it is really part of the erl_interface library,
+not the ei library.
+
+Use uint8, uint16, uint32, int8, int16, and int32 for types
+where size matters ;-) Use uint8 for buffers where we construct
+messages.
+
+NOTE!!!! Sending a "char" to macros like isupper(), isalpha() where
+the character is > 127 will cause serios problems on some
+machines/OS. The reason is that
+
+ 'char' may be unsigned, i.e. the Swedish char '�' will
+ as a number be negativ.
+
+ The implementation of isupper() and others will on some
+ machines use an array that is indexed with the incoming
+ character code. The Swedish '�' will then create an access
+ on memory outside the array!
+
+This may give a random value as a result or a segmentation
+violation error.
+
+
+******************************************************************************
+ Global variables
+******************************************************************************
+
+There are two reasons we avoid global variables:
+
+ - It is much easier to support threads without them
+
+ - On operating systems like VxWorks the global variable is global
+ to all operating system processes.
+
+There are a few global variables that are ok
+
+ ei_x_extra This is set to 100 in "ei_x_encode.c" but can be
+ changed for debugging the memory allocation.
+
+ ei_trace_distribution Enable verbose tracing on stderr.
+
+ errno In the non threaded version of the lib this
+ is a global variable.
+
+ __erl_errno This is a global handled by "ei_pthreads.c"
+
+You can check for globals using something like
+
+ % nm -g ei_fake_prog | fgrep OBJT
+
+Global variables but with local scope
+
+ erl_if_ec Global state, is ok
+
+
+******************************************************************************
+ The "long long" story
+******************************************************************************
+
+There are some functions in the 'ei' library that uses the GCC and
+VC++ "long long" type. Unfortunately this can lead to some trouble.
+
+When user code is linked with the "libei.a" the linker will extract
+all objects files needed for resolving all symbol referenses
+found. This means that you want to follow the rule that
+
+ * To reduce executable code size we use resonably small C source
+ files. One C file is one object file.
+
+ * We try to avoid unessesary dependency. For example currently almost all
+ ei_x_encode*() functions are in the same object file. Because they all
+ use the corresponding ei_encode*() function this means using one ei_x
+ function we will link in "ei_x_encode.o" object file but also all the
+ "ei_encode*.o" object files even if they are not used.
+
+But the above is not the real trouble, memory and disk is cheap these
+days. The real trouble is if we compile the 'ei' library using one
+compiler, usually GNU cc, and link with another linker than GNU ld or
+miss some runtime libraries that the GNU cc generated object files
+assume is on the target. For example currently on Solaris some "long
+long" operations will create a dependency to a "hidden" library
+"libgcc.a". For example in a library not released got references to
+"libgcc.a" '__ashldi3'
+
+ % nm -A libei.a | grep '__ashldi3'
+ libei.a[decode_longlong.o]: [6] | 0| 0|NOTY |GLOB |0 |UNDEF |__ashldi3
+ libei.a[decode_ulonglong.o]: [5] | 0| 0|NOTY |GLOB |0 |UNDEF |__ashldi3
+
+We can accept that a dependecy is created for code linked with
+"libei.a" that actually use 'ei' long long functions. But if we
+arrange the 'ei' source badly using a non "long long" functions from
+'ei' will still link in an object file that need "libgcc.a". One
+example is that in plain R9C the ei_x_encode_longlong() function is
+located in the file "ei_x_encode.c". So if any "long long" ei_x
+function is used we have an unessesary dependency on
+"ei_encode_longlong.o" and then need to link with GNU ld on with the
+user code or explicitely link with "libgcc.a". The situation can be
+visible in in plain R9C using
+
+ % nm -A erl_interface-3.4/lib/libei.a | \
+ grep 'longlong' | fgrep -v 'longlong.o'
+
+As an possibly alternative to the current solution we may include the
+object files inside the "libgcc.a" archive in the "libei.a" archive.
+The "libgcc.a" that is assumed to be used when linking can be found
+using
+
+ % gcc -print-libgcc-file-name
+
+Some links about problems and solutions using "libgcc.a"
+
+ http://www.gnu.org/software/gcc/gcc-3.0/libgcc.html
+ http://www.gnu.org/software/libc/FAQ.html
+
+The license for "libgcc.a" is a bit special and not located on the
+official sites. You have to look in the source file for the "libgcc.a"
+you use. The file is named "libgcc.c". If you don't know what gcc that
+was used for the build of for example 'r9c' you can use
+
+ % otp_build_env -o r9c | perl -ne '/(gcc-[\d\.]+)/ and print "$1\n"'
+
+Then to view the lincense do
+
+ % less `find /usr/local/share/src/gcc-REL/ -name "libgcc*.c"`
+
+
+********************************* EOF ****************************************
diff --git a/lib/erl_interface/src/auxdir/config.guess b/lib/erl_interface/src/auxdir/config.guess
new file mode 120000
index 0000000000..fefabd7dd0
--- /dev/null
+++ b/lib/erl_interface/src/auxdir/config.guess
@@ -0,0 +1 @@
+../../../../erts/autoconf/config.guess \ No newline at end of file
diff --git a/lib/erl_interface/src/auxdir/config.h.in b/lib/erl_interface/src/auxdir/config.h.in
new file mode 100644
index 0000000000..523c766993
--- /dev/null
+++ b/lib/erl_interface/src/auxdir/config.h.in
@@ -0,0 +1,277 @@
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+ systems. This function is required for `alloca.c' support on those systems.
+ */
+#undef CRAY_STACKSEG_END
+
+/* Define to 1 if using `alloca.c'. */
+#undef C_ALLOCA
+
+/* Define to 1 if you have `alloca', as a function or macro. */
+#undef HAVE_ALLOCA
+
+/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
+ */
+#undef HAVE_ALLOCA_H
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
+/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
+ don't. */
+#undef HAVE_DECL_STRERROR_R
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+#undef HAVE_DOPRNT
+
+/* Define to 1 if you have the `dup2' function. */
+#undef HAVE_DUP2
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the `fork' function. */
+#undef HAVE_FORK
+
+/* Define to 1 if you have the `gethostbyaddr' function. */
+#undef HAVE_GETHOSTBYADDR
+
+/* Define to 1 if you have the `gethostbyname' function. */
+#undef HAVE_GETHOSTBYNAME
+
+/* Define to 1 if you have the `gethostbyname_r' function. */
+#undef HAVE_GETHOSTBYNAME_R
+
+/* Define to 1 if you have the `gethostname' function. */
+#undef HAVE_GETHOSTNAME
+
+/* Define to 1 if you have the `gethrtime' function. */
+#undef HAVE_GETHRTIME
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have the <gmp.h> header file. */
+#undef HAVE_GMP_H
+
+/* Define to 1 if you have the `inet_ntoa' function. */
+#undef HAVE_INET_NTOA
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `gmp' library (-lgmp). */
+#undef HAVE_LIBGMP
+
+/* Define to 1 if you have the `m' library (-lm). */
+#undef HAVE_LIBM
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#undef HAVE_LIBRESOLV
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
+ to 0 otherwise. */
+#undef HAVE_MALLOC
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#undef HAVE_MALLOC_H
+
+/* Define to 1 if you have the `memchr' function. */
+#undef HAVE_MEMCHR
+
+/* Define to 1 if you have the `memmove' function. */
+#undef HAVE_MEMMOVE
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the `memset' function. */
+#undef HAVE_MEMSET
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <pthread/mit/pthread.h> header file. */
+#undef HAVE_MIT_PTHREAD_H
+
+/* Define to 1 if you have the <pthread.h> header file. */
+#undef HAVE_PTHREAD_H
+
+/* Define to 1 if your system has a GNU libc compatible `realloc' function,
+ and to 0 otherwise. */
+#undef HAVE_REALLOC
+
+/* Define if you have the res_gethostbyname function. */
+#undef HAVE_RES_GETHOSTBYNAME
+
+/* Define to 1 if you have the `select' function. */
+#undef HAVE_SELECT
+
+/* Define to 1 if you have the `socket' function. */
+#undef HAVE_SOCKET
+
+/* Define to 1 if you have the <stddef.h> header file. */
+#undef HAVE_STDDEF_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strchr' function. */
+#undef HAVE_STRCHR
+
+/* Define to 1 if you have the `strerror' function. */
+#undef HAVE_STRERROR
+
+/* Define to 1 if you have the `strerror_r' function. */
+#undef HAVE_STRERROR_R
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strrchr' function. */
+#undef HAVE_STRRCHR
+
+/* Define to 1 if you have the `strstr' function. */
+#undef HAVE_STRSTR
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define to 1 if you have the `uname' function. */
+#undef HAVE_UNAME
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `vfork' function. */
+#undef HAVE_VFORK
+
+/* Define to 1 if you have the <vfork.h> header file. */
+#undef HAVE_VFORK_H
+
+/* Define to 1 if you have the `vprintf' function. */
+#undef HAVE_VPRINTF
+
+/* Define to 1 if `fork' works. */
+#undef HAVE_WORKING_FORK
+
+/* Define to 1 if `vfork' works. */
+#undef HAVE_WORKING_VFORK
+
+/* Define if you have the writev function. */
+#undef HAVE_WRITEV
+
+/* Define if you have the socklen_t datatype */
+#undef HAVE_SOCKLEN_T
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Define to the type of arg 1 for `select'. */
+#undef SELECT_TYPE_ARG1
+
+/* Define to the type of args 2, 3 and 4 for `select'. */
+#undef SELECT_TYPE_ARG234
+
+/* Define to the type of arg 5 for `select'. */
+#undef SELECT_TYPE_ARG5
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+#undef STACK_DIRECTION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if strerror_r returns char *. */
+#undef STRERROR_R_CHAR_P
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define to rpl_malloc if the replacement function should be used. */
+#undef malloc
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef pid_t
+
+/* Define to rpl_realloc if the replacement function should be used. */
+#undef realloc
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define as `fork' if `vfork' does not work. */
+#undef vfork
+
+/* Define to empty if the keyword `volatile' does not work. Warning: valid
+ code using `volatile' can become incorrect without. Disable with care. */
+#undef volatile
diff --git a/lib/erl_interface/src/auxdir/config.sub b/lib/erl_interface/src/auxdir/config.sub
new file mode 120000
index 0000000000..90979e8924
--- /dev/null
+++ b/lib/erl_interface/src/auxdir/config.sub
@@ -0,0 +1 @@
+../../../../erts/autoconf/config.sub \ No newline at end of file
diff --git a/lib/erl_interface/src/auxdir/install-sh b/lib/erl_interface/src/auxdir/install-sh
new file mode 120000
index 0000000000..9422c370df
--- /dev/null
+++ b/lib/erl_interface/src/auxdir/install-sh
@@ -0,0 +1 @@
+../../../../erts/autoconf/install-sh \ No newline at end of file
diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c
new file mode 100644
index 0000000000..9ac5a93c5a
--- /dev/null
+++ b/lib/erl_interface/src/connect/ei_connect.c
@@ -0,0 +1,1738 @@
+/*
+ * %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: Connect to any node at any host. (EI version)
+ */
+
+#include "eidef.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+
+#elif VXWORKS
+#include <vxWorks.h>
+#include <hostLib.h>
+#include <selectLib.h>
+#include <ifLib.h>
+#include <sockLib.h>
+#include <taskLib.h>
+#include <inetLib.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/times.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <timers.h>
+
+#define getpid() taskIdSelf()
+
+#else /* some other unix */
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/times.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/utsname.h> /* for gen_challenge (NEED FIX?) */
+#include <time.h>
+#endif
+
+/* common includes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "eiext.h"
+#include "ei_portio.h"
+#include "ei_internal.h"
+#include "ei_connect_int.h"
+#include "ei_locking.h"
+#include "eisend.h"
+#include "eirecv.h"
+#include "eimd5.h"
+#include "putget.h"
+#include "ei_resolve.h"
+#include "ei_epmd.h"
+#include "ei_internal.h"
+
+int ei_tracelevel = 0;
+
+#define COOKIE_FILE "/.erlang.cookie"
+#define EI_MAX_HOME_PATH 1024
+
+/* FIXME why not macro? */
+static char *null_cookie = "";
+
+static int get_cookie(char *buf, int len);
+static int get_home(char *buf, int size);
+
+/* forwards */
+static unsigned gen_challenge(void);
+static void gen_digest(unsigned challenge, char cookie[],
+ unsigned char digest[16]);
+static int send_status(int fd, char *status, unsigned ms);
+static int recv_status(int fd, unsigned ms);
+static int send_challenge(int fd, char *nodename,
+ unsigned challenge, unsigned version, unsigned ms);
+static int recv_challenge(int fd, unsigned *challenge,
+ unsigned *version,
+ unsigned *flags, ErlConnect *namebuf, unsigned ms);
+static int send_challenge_reply(int fd, unsigned char digest[16],
+ unsigned challenge, unsigned ms);
+static int recv_challenge_reply(int fd,
+ unsigned our_challenge,
+ char cookie[],
+ unsigned *her_challenge, unsigned ms);
+static int send_challenge_ack(int fd, unsigned char digest[16], unsigned ms);
+static int recv_challenge_ack(int fd,
+ unsigned our_challenge,
+ char cookie[], unsigned ms);
+static int send_name(int fd, char *nodename,
+ unsigned version, unsigned ms);
+
+/* Common for both handshake types */
+static int recv_name(int fd,
+ unsigned *version,
+ unsigned *flags, ErlConnect *namebuf, unsigned ms);
+
+
+/***************************************************************************
+ *
+ * For each file descriptor returned from ei_connect() we save information
+ * about distribution protocol version, node information for this node
+ * and the cookie.
+ *
+ ***************************************************************************/
+
+typedef struct ei_socket_info_s {
+ int socket;
+ int dist_version;
+ ei_cnode cnode; /* A copy, not a pointer. We don't know when freed */
+ char cookie[EI_MAX_COOKIE_SIZE+1];
+} ei_socket_info;
+
+int ei_n_sockets = 0, ei_sz_sockets = 0;
+ei_socket_info *ei_sockets = NULL;
+#ifdef _REENTRANT
+ei_mutex_t* ei_sockets_lock = NULL;
+#endif /* _REENTRANT */
+
+
+/***************************************************************************
+ *
+ * XXX
+ *
+ ***************************************************************************/
+
+static int put_ei_socket_info(int fd, int dist_version, char* cookie, ei_cnode *ec)
+{
+ int i;
+
+#ifdef _REENTRANT
+ ei_mutex_lock(ei_sockets_lock, 0);
+#endif /* _REENTRANT */
+ for (i = 0; i < ei_n_sockets; ++i) {
+ if (ei_sockets[i].socket == fd) {
+ if (dist_version == -1) {
+ memmove(&ei_sockets[i], &ei_sockets[i+1],
+ sizeof(ei_sockets[0])*(ei_n_sockets-i-1));
+ } else {
+ ei_sockets[i].dist_version = dist_version;
+ /* Copy the content, see ei_socket_info */
+ ei_sockets[i].cnode = *ec;
+ strcpy(ei_sockets[i].cookie, cookie);
+ }
+#ifdef _REENTRANT
+ ei_mutex_unlock(ei_sockets_lock);
+#endif /* _REENTRANT */
+ return 0;
+ }
+ }
+ if (ei_n_sockets == ei_sz_sockets) {
+ ei_sz_sockets += 5;
+ ei_sockets = realloc(ei_sockets,
+ sizeof(ei_sockets[0])*ei_sz_sockets);
+ if (ei_sockets == NULL) {
+ ei_sz_sockets = ei_n_sockets = 0;
+#ifdef _REENTRANT
+ ei_mutex_unlock(ei_sockets_lock);
+#endif /* _REENTRANT */
+ return -1;
+ }
+ ei_sockets[ei_n_sockets].socket = fd;
+ ei_sockets[ei_n_sockets].dist_version = dist_version;
+ ei_sockets[i].cnode = *ec;
+ strcpy(ei_sockets[ei_n_sockets].cookie, cookie);
+ ++ei_n_sockets;
+ }
+#ifdef _REENTRANT
+ ei_mutex_unlock(ei_sockets_lock);
+#endif /* _REENTRANT */
+ return 0;
+}
+
+#if 0
+/* FIXME not used ?! */
+static int remove_ei_socket_info(int fd, int dist_version, char* cookie)
+{
+ return put_ei_socket_info(fd, -1, NULL);
+}
+#endif
+
+static ei_socket_info* get_ei_socket_info(int fd)
+{
+ int i;
+#ifdef _REENTRANT
+ ei_mutex_lock(ei_sockets_lock, 0);
+#endif /* _REENTRANT */
+ for (i = 0; i < ei_n_sockets; ++i)
+ if (ei_sockets[i].socket == fd) {
+ /*fprintf("get_ei_socket_info %d %d \"%s\"\n",
+ fd, ei_sockets[i].dist_version, ei_sockets[i].cookie);*/
+#ifdef _REENTRANT
+ ei_mutex_unlock(ei_sockets_lock);
+#endif /* _REENTRANT */
+ return &ei_sockets[i];
+ }
+#ifdef _REENTRANT
+ ei_mutex_unlock(ei_sockets_lock);
+#endif /* _REENTRANT */
+ return NULL;
+}
+
+ei_cnode *ei_fd_to_cnode(int fd)
+{
+ ei_socket_info *sockinfo = get_ei_socket_info(fd);
+ if (sockinfo == NULL) return NULL;
+ return &sockinfo->cnode;
+}
+
+/***************************************************************************
+ * XXXX
+ ***************************************************************************/
+
+int ei_distversion(int fd)
+{
+ ei_socket_info* e = get_ei_socket_info(fd);
+ if (e == NULL)
+ return -1;
+ else
+ return e->dist_version;
+}
+
+static const char* ei_cookie(int fd)
+{
+ ei_socket_info* e = get_ei_socket_info(fd);
+ if (e == NULL)
+ return NULL;
+ else
+ return e->cookie;
+}
+
+const char *ei_thisnodename(const ei_cnode* ec)
+{
+ return ec->thisnodename;
+}
+
+const char *ei_thishostname(const ei_cnode* ec)
+{
+ return ec->thishostname;
+}
+
+const char *ei_thisalivename(const ei_cnode* ec)
+{
+ return ec->thisalivename;
+}
+
+short ei_thiscreation(const ei_cnode* ec)
+{
+ return ec->creation;
+}
+
+/* FIXME: this function is not an api, why not? */
+const char *ei_thiscookie(const ei_cnode* ec)
+{
+ return (const char *)ec->ei_connect_cookie;
+}
+
+erlang_pid *ei_self(ei_cnode* ec)
+{
+ return &ec->self;
+}
+
+/* two internal functions that will let us support different cookies
+* (to be able to connect to other nodes that don't have the same
+* cookie as each other or us)
+*/
+const char *ei_getfdcookie(int fd)
+{
+ const char* r = ei_cookie(fd);
+ if (r == NULL) r = "";
+ return r;
+}
+
+/* call with cookie to set value to use on descriptor fd,
+* or specify NULL to use default
+*/
+/* FIXME why defined but not used? */
+#if 0
+static int ei_setfdcookie(ei_cnode* ec, int fd, char *cookie)
+{
+ int dist_version = ei_distversion(fd);
+
+ if (cookie == NULL)
+ cookie = ec->ei_connect_cookie;
+ return put_ei_socket_info(fd, dist_version, cookie);
+}
+#endif
+
+static int get_int32(unsigned char *s)
+{
+ return ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | (s[3] ));
+}
+
+
+#ifdef __WIN32__
+void win32_error(char *buf, int buflen)
+{
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
+ 0, /* n/a */
+ WSAGetLastError(), /* error code */
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* language */
+ buf,
+ buflen,
+ NULL);
+ return;
+}
+
+static int initWinSock(void)
+{
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int i;
+ /* FIXME problem for threaded ? */
+ static int initialized = 0;
+
+ wVersionRequested = MAKEWORD(1, 1);
+ if (!initialized) {
+ initialized = 1;
+ /* FIXME not terminate, just a message?! */
+ if ((i = WSAStartup(wVersionRequested, &wsaData))) {
+ EI_TRACE_ERR1("ei_connect_init",
+ "ERROR: can't initialize windows sockets: %d",i);
+ return 0;
+ }
+
+ if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) {
+ EI_TRACE_ERR0("initWinSock","ERROR: this version of windows "
+ "sockets not supported");
+ WSACleanup();
+ return 0;
+ }
+ }
+ return 1;
+}
+#endif
+
+/*
+* Perhaps run this routine instead of ei_connect_init/2 ?
+* Initailize by setting:
+* thishostname, thisalivename, thisnodename and thisipaddr
+*/
+int ei_connect_xinit(ei_cnode* ec, const char *thishostname,
+ const char *thisalivename, const char *thisnodename,
+ Erl_IpAddr thisipaddr, const char *cookie,
+ const short creation)
+{
+ char *dbglevel;
+
+/* FIXME this code was enabled for 'erl'_connect_xinit(), why not here? */
+#if 0
+#ifdef __WIN32__
+ if (!initWinSock()) {
+ EI_TRACE_ERR0("ei_connect_xinit","can't initiate winsock");
+ return ERL_ERROR;
+ }
+#endif
+#endif
+
+#ifdef _REENTRANT
+ if (ei_sockets_lock == NULL) {
+ ei_sockets_lock = ei_mutex_create();
+ }
+#endif /* _REENTRANT */
+
+ ec->creation = creation;
+
+ if (cookie) {
+ if (strlen(cookie) >= sizeof(ec->ei_connect_cookie)) {
+ EI_TRACE_ERR0("ei_connect_xinit",
+ "ERROR: Cookie size too large");
+ return ERL_ERROR;
+ } else {
+ strcpy(ec->ei_connect_cookie, cookie);
+ }
+ } else if (!get_cookie(ec->ei_connect_cookie, sizeof(ec->ei_connect_cookie))) {
+ return ERL_ERROR;
+ }
+
+ if (strlen(thishostname) >= sizeof(ec->thishostname)) {
+ EI_TRACE_ERR0("ei_connect_xinit","ERROR: Thishostname too long");
+ return ERL_ERROR;
+ }
+ strcpy(ec->thishostname, thishostname);
+
+ if (strlen(thisalivename) >= sizeof(ec->thisalivename)) {
+ EI_TRACE_ERR0("ei_connect_init","Thisalivename too long");
+ return ERL_ERROR;
+ }
+
+ strcpy(ec->thisalivename, thisalivename);
+
+ if (strlen(thisnodename) >= sizeof(ec->thisnodename)) {
+ EI_TRACE_ERR0("ei_connect_init","Thisnodename too long");
+ return ERL_ERROR;
+ }
+ strcpy(ec->thisnodename, thisnodename);
+
+/* FIXME right now this_ipaddr is never used */
+/* memmove(&ec->this_ipaddr, thisipaddr, sizeof(ec->this_ipaddr)); */
+
+ strcpy(ec->self.node,thisnodename);
+ ec->self.num = 0;
+ ec->self.serial = 0;
+ ec->self.creation = creation;
+
+ if ((dbglevel = getenv("EI_TRACELEVEL")) != NULL ||
+ (dbglevel = getenv("ERL_DEBUG_DIST")) != NULL)
+ ei_tracelevel = atoi(dbglevel);
+
+ return 0;
+}
+
+
+/*
+* Initialize by set: thishostname, thisalivename,
+* thisnodename and thisipaddr. At success return 0,
+* otherwise return -1.
+*/
+int ei_connect_init(ei_cnode* ec, const char* this_node_name,
+ const char *cookie, short creation)
+{
+ struct hostent *hp;
+ char thishostname[EI_MAXHOSTNAMELEN+1];
+ char thisnodename[MAXNODELEN+1];
+ char thisalivename[EI_MAXALIVELEN+1];
+
+#ifdef __WIN32__
+ if (!initWinSock()) {
+ EI_TRACE_ERR0("ei_connect_xinit","can't initiate winsock");
+ return ERL_ERROR;
+ }
+#endif /* win32 */
+#ifdef _REENTRANT
+ if (ei_sockets_lock == NULL) {
+ ei_sockets_lock = ei_mutex_create();
+ }
+#endif /* _REENTRANT */
+
+ if (gethostname(thishostname, EI_MAXHOSTNAMELEN) == -1) {
+#ifdef __WIN32__
+ EI_TRACE_ERR1("ei_connect_init","Failed to get host name: %d",
+ WSAGetLastError());
+#else
+ EI_TRACE_ERR1("ei_connect_init","Failed to get host name: %d", errno);
+#endif /* win32 */
+ return ERL_ERROR;
+ }
+
+ if (this_node_name == NULL)
+ sprintf(thisalivename, "c%d", (int) getpid());
+ else
+ strcpy(thisalivename, this_node_name);
+
+ if ((hp = ei_gethostbyname(thishostname)) == 0) {
+ /* Looking up IP given hostname fails. We must be on a standalone
+ host so let's use loopback for communication instead. */
+ if ((hp = ei_gethostbyname("localhost")) == 0) {
+#ifdef __WIN32__
+ char reason[1024];
+
+ win32_error(reason,sizeof(reason));
+ EI_TRACE_ERR2("ei_connect_init",
+ "Can't get ip address for host %s: %s",
+ thishostname, reason);
+#else
+ EI_TRACE_ERR2("ei_connect_init",
+ "Can't get ip address for host %s: %d",
+ thishostname, h_errno);
+#endif /* win32 */
+ return ERL_ERROR;
+ }
+ }
+ {
+ char* ct;
+ if (strcmp(hp->h_name, "localhost") == 0) {
+ /* We use a short node name */
+ if ((ct = strchr(thishostname, '.')) != NULL) *ct = '\0';
+ sprintf(thisnodename, "%s@%s", this_node_name, thishostname);
+ } else {
+ /* We use a short node name */
+ if ((ct = strchr(hp->h_name, '.')) != NULL) *ct = '\0';
+ strcpy(thishostname, hp->h_name);
+ sprintf(thisnodename, "%s@%s", this_node_name, hp->h_name);
+ }
+ }
+ return ei_connect_xinit(ec, thishostname, thisalivename, thisnodename,
+ (struct in_addr *)*hp->h_addr_list, cookie, creation);
+}
+
+
+/* connects to port at ip-address ip_addr
+* and returns fd to socket
+* port has to be in host byte order
+*/
+static int cnct(uint16 port, struct in_addr *ip_addr, int addr_len, unsigned ms)
+{
+ int s, res;
+ struct sockaddr_in iserv_addr;
+
+ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ erl_errno = errno;
+ return ERL_ERROR;
+ }
+
+ memset((char*)&iserv_addr, 0, sizeof(struct sockaddr_in));
+ memcpy((char*)&iserv_addr.sin_addr, (char*)ip_addr, addr_len);
+ iserv_addr.sin_family = AF_INET;
+ iserv_addr.sin_port = htons(port);
+
+ if ((res = ei_connect_t(s, (struct sockaddr*)&iserv_addr,
+ sizeof(iserv_addr),ms)) < 0) {
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ closesocket(s);
+ return ERL_ERROR;
+ }
+
+ return s;
+} /* cnct */
+
+ /*
+ * Set up a connection to a given Node, and
+ * interchange hand shake messages with it.
+ * Returns a valid file descriptor at success,
+ * otherwise a negative error code.
+*/
+int ei_connect_tmo(ei_cnode* ec, char *nodename, unsigned ms)
+{
+ char *hostname, alivename[BUFSIZ];
+ struct hostent *hp;
+#if !defined (__WIN32__)
+ /* these are needed for the call to gethostbyname_r */
+ struct hostent host;
+ char buffer[1024];
+ int ei_h_errno;
+#endif /* !win32 */
+
+ /* extract the host and alive parts from nodename */
+ if (!(hostname = strchr(nodename,'@'))) {
+ EI_TRACE_ERR0("ei_connect","Node name has no @ in name");
+ return ERL_ERROR;
+ } else {
+ strncpy(alivename, nodename, hostname - nodename);
+ alivename[hostname - nodename] = 0x0;
+ hostname++;
+ }
+
+#ifndef __WIN32__
+ hp = ei_gethostbyname_r(hostname,&host,buffer,1024,&ei_h_errno);
+ if (hp == NULL) {
+ char thishostname[EI_MAXHOSTNAMELEN+1];
+ if (gethostname(thishostname,EI_MAXHOSTNAMELEN) < 0) {
+ EI_TRACE_ERR0("ei_connect_tmo",
+ "Failed to get name of this host");
+ erl_errno = EHOSTUNREACH;
+ return ERL_ERROR;
+ } else {
+ char *ct;
+ /* We use a short node name */
+ if ((ct = strchr(thishostname, '.')) != NULL) *ct = '\0';
+ }
+ if (strcmp(hostname,thishostname) == 0)
+ /* Both nodes on same standalone host, use loopback */
+ hp = ei_gethostbyname_r("localhost",&host,buffer,1024,&ei_h_errno);
+ if (hp == NULL) {
+ EI_TRACE_ERR2("ei_connect",
+ "Can't find host for %s: %d\n",nodename,ei_h_errno);
+ erl_errno = EHOSTUNREACH;
+ return ERL_ERROR;
+ }
+ }
+#else /* __WIN32__ */
+ if ((hp = ei_gethostbyname(hostname)) == NULL) {
+ char thishostname[EI_MAXHOSTNAMELEN+1];
+ if (gethostname(thishostname,EI_MAXHOSTNAMELEN) < 0) {
+ EI_TRACE_ERR1("ei_connect_tmo",
+ "Failed to get name of this host: %d",
+ WSAGetLastError());
+ erl_errno = EHOSTUNREACH;
+ return ERL_ERROR;
+ } else {
+ char *ct;
+ /* We use a short node name */
+ if ((ct = strchr(thishostname, '.')) != NULL) *ct = '\0';
+ }
+ if (strcmp(hostname,thishostname) == 0)
+ /* Both nodes on same standalone host, use loopback */
+ hp = ei_gethostbyname("localhost");
+ if (hp == NULL) {
+ char reason[1024];
+ win32_error(reason,sizeof(reason));
+ EI_TRACE_ERR2("ei_connect",
+ "Can't find host for %s: %s",nodename,reason);
+ erl_errno = EHOSTUNREACH;
+ return ERL_ERROR;
+ }
+ }
+#endif /* win32 */
+ return ei_xconnect_tmo(ec, (Erl_IpAddr) *hp->h_addr_list, alivename, ms);
+} /* ei_connect */
+
+int ei_connect(ei_cnode* ec, char *nodename)
+{
+ return ei_connect_tmo(ec, nodename, 0);
+}
+
+
+ /* ip_addr is now in network byte order
+ *
+ * first we have to get hold of the portnumber to
+ * the node through epmd at that host
+ *
+*/
+int ei_xconnect_tmo(ei_cnode* ec, Erl_IpAddr adr, char *alivename, unsigned ms)
+{
+ struct in_addr *ip_addr=(struct in_addr *) adr;
+ int rport = 0; /*uint16 rport = 0;*/
+ int sockd;
+ int one = 1;
+ int dist = 0;
+ ErlConnect her_name;
+ unsigned her_flags, her_version;
+
+ erl_errno = EIO; /* Default error code */
+
+ EI_TRACE_CONN1("ei_xconnect","-> CONNECT attempt to connect to %s",
+ alivename);
+
+ if ((rport = ei_epmd_port_tmo(ip_addr,alivename,&dist, ms)) < 0) {
+ EI_TRACE_ERR0("ei_xconnect","-> CONNECT can't get remote port");
+ /* ei_epmd_port_tmo() has set erl_errno */
+ return ERL_NO_PORT;
+ }
+
+ /* we now have port number to enode, try to connect */
+ if((sockd = cnct((uint16)rport, ip_addr, sizeof(struct in_addr),ms)) < 0) {
+ EI_TRACE_ERR0("ei_xconnect","-> CONNECT socket connect failed");
+ /* cnct() has set erl_errno */
+ return ERL_CONNECT_FAIL;
+ }
+
+ EI_TRACE_CONN0("ei_xconnect","-> CONNECT connected to remote");
+
+ /* FIXME why connect before checking 'dist' output from ei_epmd_port() ?! */
+ if (dist <= 4) {
+ EI_TRACE_ERR0("ei_xconnect","-> CONNECT remote version not compatible");
+ goto error;
+ }
+ else {
+ unsigned our_challenge, her_challenge;
+ unsigned char our_digest[16];
+
+ if (send_name(sockd, ec->thisnodename, (unsigned) dist, ms))
+ goto error;
+ if (recv_status(sockd, ms))
+ goto error;
+ if (recv_challenge(sockd, &her_challenge, &her_version,
+ &her_flags, &her_name, ms))
+ goto error;
+ our_challenge = gen_challenge();
+ gen_digest(her_challenge, ec->ei_connect_cookie, our_digest);
+ if (send_challenge_reply(sockd, our_digest, our_challenge, ms))
+ goto error;
+ if (recv_challenge_ack(sockd, our_challenge,
+ ec->ei_connect_cookie, ms))
+ goto error;
+ put_ei_socket_info(sockd, dist, null_cookie, ec); /* FIXME check == 0 */
+ }
+
+ setsockopt(sockd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one));
+ setsockopt(sockd, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof(one));
+
+ EI_TRACE_CONN1("ei_xconnect","-> CONNECT (ok) remote = %s",alivename);
+
+ erl_errno = 0;
+ return sockd;
+
+error:
+ EI_TRACE_ERR0("ei_xconnect","-> CONNECT failed");
+ closesocket(sockd);
+ return ERL_ERROR;
+} /* ei_xconnect */
+
+int ei_xconnect(ei_cnode* ec, Erl_IpAddr adr, char *alivename)
+{
+ return ei_xconnect_tmo(ec, adr, alivename, 0);
+}
+
+
+ /*
+ * For symmetry reasons
+*/
+#if 0
+int ei_close_connection(int fd)
+{
+ return closesocket(fd);
+} /* ei_close_connection */
+#endif
+
+ /*
+ * Accept and initiate a connection from an other
+ * Erlang node. Return a file descriptor at success,
+ * otherwise -1;
+*/
+int ei_accept(ei_cnode* ec, int lfd, ErlConnect *conp)
+{
+ return ei_accept_tmo(ec, lfd, conp, 0);
+}
+
+int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms)
+{
+ int fd;
+ struct sockaddr_in cli_addr;
+ int cli_addr_len=sizeof(struct sockaddr_in);
+ unsigned her_version, her_flags;
+ ErlConnect her_name;
+
+ erl_errno = EIO; /* Default error code */
+
+ EI_TRACE_CONN0("ei_accept","<- ACCEPT waiting for connection");
+
+ if ((fd = ei_accept_t(lfd, (struct sockaddr*) &cli_addr,
+ &cli_addr_len, ms )) < 0) {
+ EI_TRACE_ERR0("ei_accept","<- ACCEPT socket accept failed");
+ erl_errno = (fd == -2) ? ETIMEDOUT : EIO;
+ goto error;
+ }
+
+ EI_TRACE_CONN0("ei_accept","<- ACCEPT connected to remote");
+
+ if (recv_name(fd, &her_version, &her_flags, &her_name, ms)) {
+ EI_TRACE_ERR0("ei_accept","<- ACCEPT initial ident failed");
+ goto error;
+ }
+
+ if (her_version <= 4) {
+ EI_TRACE_ERR0("ei_accept","<- ACCEPT remote version not compatible");
+ goto error;
+ }
+ else {
+ unsigned our_challenge;
+ unsigned her_challenge;
+ unsigned char our_digest[16];
+
+ if (send_status(fd,"ok", ms))
+ goto error;
+ our_challenge = gen_challenge();
+ if (send_challenge(fd, ec->thisnodename,
+ our_challenge, her_version, ms))
+ goto error;
+ if (recv_challenge_reply(fd, our_challenge,
+ ec->ei_connect_cookie,
+ &her_challenge, ms))
+ goto error;
+ gen_digest(her_challenge, ec->ei_connect_cookie, our_digest);
+ if (send_challenge_ack(fd, our_digest, ms))
+ goto error;
+ put_ei_socket_info(fd, her_version, null_cookie, ec);
+ }
+ if (conp)
+ *conp = her_name;
+
+ EI_TRACE_CONN1("ei_accept","<- ACCEPT (ok) remote = %s",her_name.nodename);
+
+ erl_errno = 0; /* No error */
+ return fd;
+
+error:
+ EI_TRACE_ERR0("ei_accept","<- ACCEPT failed");
+ closesocket(fd);
+ return ERL_ERROR;
+} /* ei_accept */
+
+
+/* Receives a message from an Erlang socket.
+ * If the message was a TICK it is immediately
+ * answered. Returns: ERL_ERROR, ERL_TICK or
+ * the number of bytes read.
+ */
+int ei_receive_tmo(int fd, unsigned char *bufp, int bufsize, unsigned ms)
+{
+ int len;
+ unsigned char fourbyte[4]={0,0,0,0};
+ int res;
+
+ if ((res = ei_read_fill_t(fd, (char *) bufp, 4, ms)) != 4) {
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return ERL_ERROR;
+ }
+
+ /* Tick handling */
+ if ((len = get_int32(bufp)) == ERL_TICK)
+ {
+ ei_write_fill_t(fd, (char *) fourbyte, 4, ms);
+ /* FIXME ok to ignore error or timeout? */
+ erl_errno = EAGAIN;
+ return ERL_TICK;
+ }
+ else if (len > bufsize)
+ {
+ /* FIXME: We should drain the message. */
+ erl_errno = EMSGSIZE;
+ return ERL_ERROR;
+ }
+ else if ((res = ei_read_fill_t(fd, (char *) bufp, len, ms)) != len)
+ {
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return ERL_ERROR;
+ }
+
+ return len;
+
+}
+
+int ei_receive(int fd, unsigned char *bufp, int bufsize)
+{
+ return ei_receive_tmo(fd, bufp, bufsize, 0);
+}
+
+int ei_reg_send_tmo(ei_cnode* ec, int fd, char *server_name,
+ char* buf, int len, unsigned ms)
+{
+ erlang_pid *self = ei_self(ec);
+ self->num = fd;
+
+ /* erl_errno and return code is set by ei_reg_send_encoded_tmo() */
+ return ei_send_reg_encoded_tmo(fd, self, server_name, buf, len, ms);
+}
+
+
+int ei_reg_send(ei_cnode* ec, int fd, char *server_name, char* buf, int len)
+{
+ return ei_reg_send_tmo(ec,fd,server_name,buf,len,0);
+}
+
+/*
+* Sends an Erlang message to a process at an Erlang node
+*/
+int ei_send_tmo(int fd, erlang_pid* to, char* buf, int len, unsigned ms)
+{
+ /* erl_errno and return code is set by ei_reg_send_encoded_tmo() */
+ return ei_send_encoded_tmo(fd, to, buf, len, ms);
+}
+
+int ei_send(int fd, erlang_pid* to, char* buf, int len)
+{
+ return ei_send_tmo(fd, to, buf, len, 0);
+}
+
+
+/*
+* Try to receive an Erlang message on a given socket. Returns
+* ERL_TICK, ERL_MSG, or ERL_ERROR. Sets `erl_errno' on ERL_ERROR and
+* ERL_TICK (to EAGAIN in the latter case).
+*/
+
+int ei_do_receive_msg(int fd, int staticbuffer_p,
+ erlang_msg* msg, ei_x_buff* x, unsigned ms)
+{
+ int msglen;
+ int i;
+
+ if (!(i=ei_recv_internal(fd, &x->buff, &x->buffsz, msg, &msglen,
+ staticbuffer_p, ms))) {
+ erl_errno = EAGAIN;
+ return ERL_TICK;
+ }
+ if (i<0) {
+ /* erl_errno set by ei_recv_internal() */
+ return ERL_ERROR;
+ }
+ if (staticbuffer_p && msglen > x->buffsz)
+ {
+ erl_errno = EMSGSIZE;
+ return ERL_ERROR;
+ }
+ x->index = x->buffsz;
+ switch (msg->msgtype) { /* FIXME are these all? */
+ case ERL_SEND:
+ case ERL_REG_SEND:
+ case ERL_LINK:
+ case ERL_UNLINK:
+ case ERL_GROUP_LEADER:
+ case ERL_EXIT:
+ case ERL_EXIT2:
+ case ERL_NODE_LINK:
+ return ERL_MSG;
+
+ default:
+ /*if (emsg->to) 'erl'_free_term(emsg->to);
+ if (emsg->from) 'erl'_free_term(emsg->from);
+ if (emsg->msg) 'erl'_free_term(emsg->msg);
+ emsg->to = NULL;
+ emsg->from = NULL;
+ emsg->msg = NULL;*/
+
+ erl_errno = EIO;
+ return ERL_ERROR;
+ }
+} /* do_receive_msg */
+
+
+int ei_receive_msg(int fd, erlang_msg* msg, ei_x_buff* x)
+{
+ return ei_do_receive_msg(fd, 1, msg, x, 0);
+}
+
+int ei_xreceive_msg(int fd, erlang_msg *msg, ei_x_buff *x)
+{
+ return ei_do_receive_msg(fd, 0, msg, x, 0);
+}
+
+int ei_receive_msg_tmo(int fd, erlang_msg* msg, ei_x_buff* x, unsigned ms)
+{
+ return ei_do_receive_msg(fd, 1, msg, x, ms);
+}
+
+int ei_xreceive_msg_tmo(int fd, erlang_msg *msg, ei_x_buff *x, unsigned ms)
+{
+ return ei_do_receive_msg(fd, 0, msg, x, ms);
+}
+
+/*
+* The RPC consists of two parts, send and receive.
+* Here is the send part !
+* { PidFrom, { call, Mod, Fun, Args, user }}
+*/
+/*
+* Now returns non-negative number for success, negative for failure.
+*/
+int ei_rpc_to(ei_cnode *ec, int fd, char *mod, char *fun,
+ const char *buf, int len)
+{
+
+ ei_x_buff x;
+ erlang_pid *self = ei_self(ec);
+ self->num = fd;
+
+ /* encode header */
+ ei_x_new_with_version(&x);
+ ei_x_encode_tuple_header(&x, 2); /* A */
+
+ self->num = fd;
+ ei_x_encode_pid(&x, self); /* A 1 */
+
+ ei_x_encode_tuple_header(&x, 5); /* B A 2 */
+ ei_x_encode_atom(&x, "call"); /* B 1 */
+ ei_x_encode_atom(&x, mod); /* B 2 */
+ ei_x_encode_atom(&x, fun); /* B 3 */
+ ei_x_append_buf(&x, buf, len); /* B 4 */
+ ei_x_encode_atom(&x, "user"); /* B 5 */
+
+ /* ei_x_encode_atom(&x,"user"); */
+ ei_send_reg_encoded(fd, self, "rex", x.buff, x.index);
+ ei_x_free(&x);
+
+ return 0;
+} /* rpc_to */
+
+ /*
+ * And here is the rpc receiving part. A negative
+ * timeout means 'infinity'. Returns either of: ERL_MSG,
+ * ERL_TICK, ERL_ERROR or ERL_TIMEOUT.
+*/
+int ei_rpc_from(ei_cnode *ec, int fd, int timeout, erlang_msg *msg,
+ ei_x_buff *x)
+{
+ fd_set readmask;
+ struct timeval tv;
+ struct timeval *t = NULL;
+
+ if (timeout >= 0) {
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ t = &tv;
+ }
+
+ FD_ZERO(&readmask);
+ FD_SET(fd,&readmask);
+
+ switch (select(fd+1, &readmask, NULL, NULL, t)) {
+ case -1:
+ erl_errno = EIO;
+ return ERL_ERROR;
+
+ case 0:
+ erl_errno = ETIMEDOUT;
+ return ERL_TIMEOUT;
+
+ default:
+ if (FD_ISSET(fd, &readmask)) {
+ return ei_xreceive_msg(fd, msg, x);
+ } else {
+ erl_errno = EIO;
+ return ERL_ERROR;
+ }
+ }
+} /* rpc_from */
+
+ /*
+ * A true RPC. It return a NULL pointer
+ * in case of failure, otherwise a valid
+ * (ETERM *) pointer containing the reply
+ */
+int ei_rpc(ei_cnode* ec, int fd, char *mod, char *fun,
+ const char* inbuf, int inbuflen, ei_x_buff* x)
+{
+ int i, index;
+ ei_term t;
+ erlang_msg msg;
+ char rex[MAXATOMLEN+1];
+
+ if (ei_rpc_to(ec, fd, mod, fun, inbuf, inbuflen) < 0) {
+ return -1;
+ }
+ /* FIXME are we not to reply to the tick? */
+ while ((i = ei_rpc_from(ec, fd, ERL_NO_TIMEOUT, &msg, x)) == ERL_TICK)
+ ;
+
+ if (i == ERL_ERROR) return -1;
+ /*ep = 'erl'_element(2,emsg.msg);*/ /* {RPC_Tag, RPC_Reply} */
+ index = 0;
+ if (ei_decode_version(x->buff, &index, &i) < 0
+ || ei_decode_ei_term(x->buff, &index, &t) < 0)
+ return -1; /* FIXME ei_decode_version don't set erl_errno as before */
+ /* FIXME this is strange, we don't check correct "rex" atom
+ and we let it pass if not ERL_SMALL_TUPLE_EXT and arity == 2 */
+ if (t.ei_type == ERL_SMALL_TUPLE_EXT && t.arity == 2)
+ if (ei_decode_atom(x->buff, &index, rex) < 0)
+ return -1;
+ /* remove header */
+ x->index -= index;
+ memmove(x->buff, &x->buff[index], x->index);
+ return 0;
+}
+
+
+ /*
+ ** Handshake
+*/
+
+
+/* FROM RTP RFC 1889 (except that we use all bits, bug in RFC?) */
+static unsigned int md_32(char* string, int length)
+{
+ MD5_CTX ctx;
+ union {
+ char c[16];
+ unsigned x[4];
+ } digest;
+ ei_MD5Init(&ctx);
+ ei_MD5Update(&ctx, (unsigned char *) string,
+ (unsigned) length);
+ ei_MD5Final((unsigned char *) digest.c, &ctx);
+ return (digest.x[0] ^ digest.x[1] ^ digest.x[2] ^ digest.x[3]);
+}
+
+#if defined(__WIN32__)
+unsigned int gen_challenge(void)
+{
+ struct {
+ SYSTEMTIME tv;
+ DWORD cpu;
+ int pid;
+ } s;
+ GetSystemTime(&s.tv);
+ s.cpu = GetTickCount();
+ s.pid = getpid();
+ return md_32((char*) &s, sizeof(s));
+}
+
+#elif defined(VXWORKS)
+
+static unsigned int gen_challenge(void)
+{
+ struct {
+ struct timespec tv;
+ clock_t cpu;
+ int pid;
+ } s;
+ s.cpu = clock();
+ clock_gettime(CLOCK_REALTIME, &s.tv);
+ s.pid = getpid();
+ return md_32((char*) &s, sizeof(s));
+}
+
+#else /* some unix */
+
+static unsigned int gen_challenge(void)
+{
+ struct {
+ struct timeval tv;
+ clock_t cpu;
+ pid_t pid;
+ u_long hid;
+ uid_t uid;
+ gid_t gid;
+ struct utsname name;
+ } s;
+
+ gettimeofday(&s.tv, 0);
+ uname(&s.name);
+ s.cpu = clock();
+ s.pid = getpid();
+ s.hid = gethostid();
+ s.uid = getuid();
+ s.gid = getgid();
+
+ return md_32((char*) &s, sizeof(s));
+}
+#endif
+
+static void gen_digest(unsigned challenge, char cookie[],
+ unsigned char digest[16])
+{
+ MD5_CTX c;
+
+ char chbuf[21];
+
+ sprintf(chbuf,"%u", challenge);
+ ei_MD5Init(&c);
+ ei_MD5Update(&c, (unsigned char *) cookie,
+ (unsigned) strlen(cookie));
+ ei_MD5Update(&c, (unsigned char *) chbuf,
+ (unsigned) strlen(chbuf));
+ ei_MD5Final(digest, &c);
+}
+
+
+static char *hex(char digest[16], char buff[33])
+{
+ static char tab[] = "0123456789abcdef";
+ unsigned char *d = (unsigned char *) digest;
+ //static char buff[sizeof(digest)*2 + 1];
+ char *p = buff;
+ int i;
+
+ for (i = 0; i < sizeof(digest); ++i) {
+ *p++ = tab[(int)((*d) >> 4)];
+ *p++ = tab[(int)((*d++) & 0xF)];
+ }
+ *p = '\0';
+ return buff;
+}
+
+static int read_2byte_package(int fd, char **buf, int *buflen,
+ int *is_static, unsigned ms)
+{
+ unsigned char nbuf[2];
+ unsigned char *x = nbuf;
+ unsigned len;
+ int res;
+
+ if((res = ei_read_fill_t(fd, (char *)nbuf, 2, ms)) != 2) {
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+ len = get16be(x);
+
+ if (len > *buflen) {
+ if (*is_static) {
+ char *tmp = malloc(len);
+ if (!tmp) {
+ erl_errno = ENOMEM;
+ return -1;
+ }
+ *buf = tmp;
+ *is_static = 0;
+ *buflen = len;
+ } else {
+ char *tmp = realloc(*buf, len);
+ if (!tmp) {
+ erl_errno = ENOMEM;
+ return -1;
+ }
+ *buf = tmp;
+ *buflen = len;
+ }
+ }
+ if ((res = ei_read_fill_t(fd, *buf, len, ms)) != len) {
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+ return len;
+}
+
+
+static int send_status(int fd, char *status, unsigned ms)
+{
+ char *buf, *s;
+ char dbuf[DEFBUF_SIZ];
+ int siz = strlen(status) + 1 + 2;
+ int res;
+
+ buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf;
+ if (!buf) {
+ erl_errno = ENOMEM;
+ return -1;
+ }
+ s = buf;
+ put16be(s,siz - 2);
+ put8(s, 's');
+ memcpy(s, status, strlen(status));
+ if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) {
+ EI_TRACE_ERR0("send_status","-> SEND_STATUS socket write failed");
+ if (buf != dbuf)
+ free(buf);
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+ EI_TRACE_CONN1("send_status","-> SEND_STATUS (%s)",status);
+
+ if (buf != dbuf)
+ free(buf);
+ return 0;
+}
+
+static int recv_status(int fd, unsigned ms)
+{
+ char dbuf[DEFBUF_SIZ];
+ char *buf = dbuf;
+ int is_static = 1;
+ int buflen = DEFBUF_SIZ;
+ int rlen;
+
+ if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) <= 0) {
+ EI_TRACE_ERR1("recv_status",
+ "<- RECV_STATUS socket read failed (%d)", rlen);
+ goto error;
+ }
+ if (rlen == 3 && buf[0] == 's' && buf[1] == 'o' &&
+ buf[2] == 'k') {
+ if (!is_static)
+ free(buf);
+ EI_TRACE_CONN0("recv_status","<- RECV_STATUS (ok)");
+ return 0;
+ }
+error:
+ if (!is_static)
+ free(buf);
+ return -1;
+}
+
+/* FIXME fix the signed/unsigned mess..... */
+
+static int send_name_or_challenge(int fd, char *nodename,
+ int f_chall,
+ unsigned challenge,
+ unsigned version,
+ unsigned ms)
+{
+ char *buf;
+ unsigned char *s;
+ char dbuf[DEFBUF_SIZ];
+ int siz = 2 + 1 + 2 + 4 + strlen(nodename);
+ const char* function[] = {"SEND_NAME", "SEND_CHALLENGE"};
+ int res;
+
+ if (f_chall)
+ siz += 4;
+ buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf;
+ if (!buf) {
+ erl_errno = ENOMEM;
+ return -1;
+ }
+ s = (unsigned char *)buf;
+ put16be(s,siz - 2);
+ put8(s, 'n');
+ put16be(s, version);
+ put32be(s, (DFLAG_EXTENDED_REFERENCES
+ | DFLAG_EXTENDED_PIDS_PORTS
+ | DFLAG_FUN_TAGS
+ | DFLAG_NEW_FUN_TAGS));
+ if (f_chall)
+ put32be(s, challenge);
+ memcpy(s, nodename, strlen(nodename));
+
+ if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) {
+ EI_TRACE_ERR1("send_name_or_challenge",
+ "-> %s socket write failed", function[f_chall]);
+ if (buf != dbuf)
+ free(buf);
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+
+ if (buf != dbuf)
+ free(buf);
+ return 0;
+}
+
+static int recv_challenge(int fd, unsigned *challenge,
+ unsigned *version,
+ unsigned *flags, ErlConnect *namebuf, unsigned ms)
+{
+ char dbuf[DEFBUF_SIZ];
+ char *buf = dbuf;
+ int is_static = 1;
+ int buflen = DEFBUF_SIZ;
+ int rlen;
+ char *s;
+ struct sockaddr_in sin;
+ socklen_t sin_len = sizeof(sin);
+ char tag;
+
+ erl_errno = EIO; /* Default */
+
+ if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) <= 0) {
+ EI_TRACE_ERR1("recv_challenge",
+ "<- RECV_CHALLENGE socket read failed (%d)",rlen);
+ goto error;
+ }
+ if ((rlen - 11) > MAXNODELEN) {
+ EI_TRACE_ERR1("recv_challenge",
+ "<- RECV_CHALLENGE nodename too long (%d)",rlen - 11);
+ goto error;
+ }
+ s = buf;
+ if ((tag = get8(s)) != 'n') {
+ EI_TRACE_ERR2("recv_challenge",
+ "<- RECV_CHALLENGE incorrect tag, "
+ "expected 'n' got '%c' (%u)",tag,tag);
+ goto error;
+ }
+ *version = get16be(s);
+ *flags = get32be(s);
+ *challenge = get32be(s);
+
+ if (!(*flags & DFLAG_EXTENDED_REFERENCES)) {
+ EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE peer cannot "
+ "handle extended references");
+ goto error;
+ }
+
+ if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)
+ && !ei_internal_use_r9_pids_ports()) {
+ EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE peer cannot "
+ "handle extended pids and ports");
+ erl_errno = EIO;
+ goto error;
+ }
+
+
+ if (getpeername(fd, (struct sockaddr *) &sin, &sin_len) < 0) {
+ EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE can't get peername");
+ erl_errno = errno;
+ goto error;
+ }
+ memcpy(namebuf->ipadr, &(sin.sin_addr.s_addr),
+ sizeof(sin.sin_addr.s_addr));
+ memcpy(namebuf->nodename, s, rlen - 11);
+ namebuf->nodename[rlen - 11] = '\0';
+ if (!is_static)
+ free(buf);
+ EI_TRACE_CONN4("recv_challenge","<- RECV_CHALLENGE (ok) node = %s, "
+ "version = %u, "
+ "flags = %u, "
+ "challenge = %d",
+ namebuf->nodename,
+ *version,
+ *flags,
+ *challenge
+ );
+ erl_errno = 0;
+ return 0;
+error:
+ if (!is_static)
+ free(buf);
+ return -1;
+}
+
+static int send_challenge_reply(int fd, unsigned char digest[16],
+ unsigned challenge, unsigned ms)
+{
+ char *s;
+ char buf[DEFBUF_SIZ];
+ int siz = 2 + 1 + 4 + 16;
+ int res;
+
+ s = buf;
+ put16be(s,siz - 2);
+ put8(s, 'r');
+ put32be(s, challenge);
+ memcpy(s, digest, 16);
+
+ if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) {
+ EI_TRACE_ERR0("send_challenge_reply",
+ "-> SEND_CHALLENGE_REPLY socket write failed");
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+
+ if (ei_tracelevel >= 3) {
+ char buffer[33];
+ EI_TRACE_CONN2("send_challenge_reply",
+ "-> SEND_CHALLENGE_REPLY (ok) challenge = %d, digest = %s",
+ challenge,hex((char*)digest, buffer));
+ }
+ return 0;
+}
+
+static int recv_challenge_reply (int fd,
+ unsigned our_challenge,
+ char cookie[],
+ unsigned *her_challenge,
+ unsigned ms)
+{
+ char dbuf[DEFBUF_SIZ];
+ char *buf = dbuf;
+ int is_static = 1;
+ int buflen = DEFBUF_SIZ;
+ int rlen;
+ char *s;
+ char tag;
+ char her_digest[16], expected_digest[16];
+
+ erl_errno = EIO; /* Default */
+
+ if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) != 21) {
+ EI_TRACE_ERR1("recv_challenge_reply",
+ "<- RECV_CHALLENGE_REPLY socket read failed (%d)",rlen);
+ goto error;
+ }
+
+ s = buf;
+ if ((tag = get8(s)) != 'r') {
+ EI_TRACE_ERR2("recv_challenge_reply",
+ "<- RECV_CHALLENGE_REPLY incorrect tag, "
+ "expected 'r' got '%c' (%u)",tag,tag);
+ goto error;
+ }
+ *her_challenge = get32be(s);
+ memcpy(her_digest, s, 16);
+ gen_digest(our_challenge, cookie, (unsigned char*)expected_digest);
+ if (memcmp(her_digest, expected_digest, 16)) {
+ EI_TRACE_ERR0("recv_challenge_reply",
+ "<- RECV_CHALLENGE_REPLY authorization failure");
+ goto error;
+ }
+ if (!is_static)
+ free(buf);
+
+
+ if (ei_tracelevel >= 3) {
+ char buffer[33];
+ EI_TRACE_CONN2("recv_challenge_reply",
+ "<- RECV_CHALLENGE_REPLY (ok) challenge = %u, digest = %s",
+ *her_challenge,hex(her_digest,buffer));
+ }
+ erl_errno = 0;
+ return 0;
+
+error:
+ if (!is_static)
+ free(buf);
+ return -1;
+}
+
+static int send_challenge_ack(int fd, unsigned char digest[16], unsigned ms)
+{
+ char *s;
+ char buf[DEFBUF_SIZ];
+ int siz = 2 + 1 + 16;
+ int res;
+
+ s = buf;
+
+ put16be(s,siz - 2);
+ put8(s, 'a');
+ memcpy(s, digest, 16);
+
+ if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) {
+ EI_TRACE_ERR0("recv_challenge_reply",
+ "-> SEND_CHALLENGE_ACK socket write failed");
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+
+ if (ei_tracelevel >= 3) {
+ char buffer[33];
+ EI_TRACE_CONN1("recv_challenge_reply",
+ "-> SEND_CHALLENGE_ACK (ok) digest = %s",hex((char *)digest,buffer));
+ }
+
+ return 0;
+}
+
+static int recv_challenge_ack(int fd,
+ unsigned our_challenge,
+ char cookie[], unsigned ms)
+{
+ char dbuf[DEFBUF_SIZ];
+ char *buf = dbuf;
+ int is_static = 1;
+ int buflen = DEFBUF_SIZ;
+ int rlen;
+ char *s;
+ char tag;
+ char her_digest[16], expected_digest[16];
+
+ erl_errno = EIO; /* Default */
+
+ if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) != 17) {
+ EI_TRACE_ERR1("recv_challenge_ack",
+ "<- RECV_CHALLENGE_ACK socket read failed (%d)",rlen);
+ goto error;
+ }
+
+ s = buf;
+ if ((tag = get8(s)) != 'a') {
+ EI_TRACE_ERR2("recv_challenge_ack",
+ "<- RECV_CHALLENGE_ACK incorrect tag, "
+ "expected 'a' got '%c' (%u)",tag,tag);
+ goto error;
+ }
+ memcpy(her_digest, s, 16);
+ gen_digest(our_challenge, cookie, (unsigned char *)expected_digest);
+ if (memcmp(her_digest, expected_digest, 16)) {
+ EI_TRACE_ERR0("recv_challenge_ack",
+ "<- RECV_CHALLENGE_ACK authorization failure");
+ goto error;
+ }
+ if (!is_static)
+ free(buf);
+
+ if (ei_tracelevel >= 3) {
+ char buffer[33];
+ EI_TRACE_CONN1("recv_challenge_ack",
+ "<- RECV_CHALLENGE_ACK (ok) digest = %s",hex(her_digest,buffer));
+ }
+ erl_errno = 0;
+ return 0;
+
+error:
+ if (!is_static)
+ free(buf);
+ return -1;
+}
+
+static int send_name(int fd, char *nodename, unsigned version, unsigned ms)
+{
+ return send_name_or_challenge(fd, nodename, 0, 0, version, ms);
+}
+
+static int send_challenge(int fd, char *nodename,
+ unsigned challenge, unsigned version, unsigned ms)
+{
+ return send_name_or_challenge(fd, nodename, 1, challenge, version, ms);
+}
+
+static int recv_name(int fd,
+ unsigned *version,
+ unsigned *flags, ErlConnect *namebuf, unsigned ms)
+{
+ char dbuf[DEFBUF_SIZ];
+ char *buf = dbuf;
+ int is_static = 1;
+ int buflen = DEFBUF_SIZ;
+ int rlen;
+ char *s;
+ struct sockaddr_in sin;
+ socklen_t sin_len = sizeof(sin);
+ char tag;
+
+ erl_errno = EIO; /* Default */
+
+ if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) <= 0) {
+ EI_TRACE_ERR1("recv_name","<- RECV_NAME socket read failed (%d)",rlen);
+ goto error;
+ }
+ if ((rlen - 7) > MAXNODELEN) {
+ EI_TRACE_ERR1("recv_name","<- RECV_NAME nodename too long (%d)",rlen-7);
+ goto error;
+ }
+ s = buf;
+ tag = get8(s);
+ if (tag != 'n') {
+ EI_TRACE_ERR2("recv_name","<- RECV_NAME incorrect tag, "
+ "expected 'n' got '%c' (%u)",tag,tag);
+ goto error;
+ }
+ *version = get16be(s);
+ *flags = get32be(s);
+
+ if (!(*flags & DFLAG_EXTENDED_REFERENCES)) {
+ EI_TRACE_ERR0("recv_name","<- RECV_NAME peer cannot handle"
+ "extended references");
+ goto error;
+ }
+
+ if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)
+ && !ei_internal_use_r9_pids_ports()) {
+ EI_TRACE_ERR0("recv_name","<- RECV_NAME peer cannot "
+ "handle extended pids and ports");
+ erl_errno = EIO;
+ goto error;
+ }
+
+ if (getpeername(fd, (struct sockaddr *) &sin, &sin_len) < 0) {
+ EI_TRACE_ERR0("recv_name","<- RECV_NAME can't get peername");
+ erl_errno = errno;
+ goto error;
+ }
+ memcpy(namebuf->ipadr, &(sin.sin_addr.s_addr),
+ sizeof(sin.sin_addr.s_addr));
+ memcpy(namebuf->nodename, s, rlen - 7);
+ namebuf->nodename[rlen - 7] = '\0';
+ if (!is_static)
+ free(buf);
+ EI_TRACE_CONN3("recv_name",
+ "<- RECV_NAME (ok) node = %s, version = %u, flags = %u",
+ namebuf->nodename,*version,*flags);
+ erl_errno = 0;
+ return 0;
+
+error:
+ if (!is_static)
+ free(buf);
+ return -1;
+}
+
+/***************************************************************************
+ *
+ * Returns 1 on success and 0 on failure.
+ *
+ ***************************************************************************/
+
+
+/* size is the buffer size, e.i. string length + 1 */
+
+static int get_home(char *buf, int size)
+{
+ char* homedrive;
+ char* homepath;
+
+#ifdef __WIN32__
+ homedrive = getenv("HOMEDRIVE");
+ homepath = getenv("HOMEPATH");
+#else
+ homedrive = "";
+ homepath = getenv("HOME");
+#endif
+
+ if (!homedrive || !homepath) {
+ buf[0] = '.';
+ buf[1] = '\0';
+ return 1;
+ } else if (strlen(homedrive)+strlen(homepath) < size-1) {
+ strcpy(buf, homedrive);
+ strcat(buf, homepath);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int get_cookie(char *buf, int bufsize)
+{
+ char fname[EI_MAX_HOME_PATH + sizeof(COOKIE_FILE) + 1];
+ int fd;
+ int len;
+ unsigned char next_c;
+
+ if (!get_home(fname, EI_MAX_HOME_PATH+1)) {
+ fprintf(stderr,"<ERROR> get_cookie: too long path to home");
+ return 0;
+ }
+
+ strcat(fname, COOKIE_FILE);
+ if ((fd = open(fname, O_RDONLY, 0777)) < 0) {
+ fprintf(stderr,"<ERROR> get_cookie: can't open cookie file");
+ return 0;
+ }
+
+ if ((len = read(fd, buf, bufsize-1)) < 0) {
+ fprintf(stderr,"<ERROR> get_cookie: reading cookie file");
+ close(fd);
+ return 0;
+ }
+
+ /* If more to read it is too long. Not 100% correct test but will do. */
+ if (read(fd, &next_c, 1) > 0 && !isspace(next_c)) {
+ fprintf(stderr,"<ERROR> get_cookie: cookie in %s is too long",fname);
+ close(fd);
+ return 0;
+ }
+
+ close(fd);
+
+ /* Remove all newlines after the first newline */
+ buf[len] = '\0'; /* Terminate string */
+ len = strcspn(buf,"\r\n");
+ buf[len] = '\0'; /* Terminate string again */
+
+ return 1; /* Success! */
+}
diff --git a/lib/erl_interface/src/connect/ei_connect_int.h b/lib/erl_interface/src/connect/ei_connect_int.h
new file mode 100644
index 0000000000..9926f799df
--- /dev/null
+++ b/lib/erl_interface/src/connect/ei_connect_int.h
@@ -0,0 +1,114 @@
+/*
+ * %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: Connect to any node at any host. (EI version)
+*/
+
+/* FIXME far to many includes here... */
+
+/* some send() functions use buffer on heap for "small" messages */
+/* messages larger than this require call to malloc() */
+
+#ifndef _EI_CONNECT_H
+#define _EI_CONNECT_H
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+
+#elif VXWORKS
+#include <vxWorks.h>
+#include <hostLib.h>
+#include <selectLib.h>
+#include <ifLib.h>
+#include <sockLib.h>
+#include <taskLib.h>
+#include <inetLib.h>
+#include <ioLib.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/times.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <timers.h>
+
+#define getpid() taskIdSelf()
+extern int h_errno;
+
+#else /* some other unix */
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/times.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/utsname.h> /* for gen_challenge (NEED FIX?) */
+#endif
+
+/* FIXME remove duplicate defintions */
+
+#define DEFBUF_SIZ 100
+
+/* rpc_from() uses a buffer this size */
+#ifndef MAX_RECEIVE_BUF
+# define MAX_RECEIVE_BUF 32*1024
+#endif
+
+/* Distribution capability flags */
+#define DFLAG_PUBLISHED 1
+#define DFLAG_ATOM_CACHE 2
+#define DFLAG_EXTENDED_REFERENCES 4
+#define DFLAG_DIST_MONITOR 8
+#define DFLAG_FUN_TAGS 16
+#define DFLAG_NEW_FUN_TAGS 0x80
+#define DFLAG_EXTENDED_PIDS_PORTS 0x100
+
+ei_cnode *ei_fd_to_cnode(int fd);
+int ei_distversion(int fd);
+const char* ei_getfdcookie(int fd);
+short ei_thiscreation(const ei_cnode* ec);
+const char *ei_thiscookie(const ei_cnode* ec);
+
+int ei_do_receive_msg(int fd, int staticbuffer_p,
+ erlang_msg* msg, ei_x_buff* x, unsigned ms);
+
+#endif /* _EI_CONNECT_H */
diff --git a/lib/erl_interface/src/connect/ei_resolve.c b/lib/erl_interface/src/connect/ei_resolve.c
new file mode 100644
index 0000000000..42aeab22b1
--- /dev/null
+++ b/lib/erl_interface/src/connect/ei_resolve.c
@@ -0,0 +1,645 @@
+/*
+ * %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%
+ */
+/*
+ * Interface functions to different versions of gethostbyname
+ */
+
+#ifdef VXWORKS
+#include <vxWorks.h>
+#include <stdio.h>
+#include <semLib.h>
+#include <hostLib.h>
+#include <resolvLib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <symLib.h>
+#include <sysSymTbl.h>
+
+#elif __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+
+#else /* unix of some kind */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/param.h>
+#endif
+
+/* common to all platforms */
+#include "eidef.h"
+#include "ei_resolve.h"
+#include "ei_locking.h"
+
+#ifdef HAVE_GETHOSTBYNAME_R
+
+void ei_init_resolve(void)
+{
+ return; /* Do nothing */
+}
+
+#else /* !HAVE_GETHOSTBYNAME_R */
+
+/* we have our own in that case */
+
+/* Make sure this semaphore has been initialized somewhere first. This
+ * should probably be done from 'erl'_init() but we do it in the first
+ * call to gethostbyname_r() or gethostbyaddr_r().
+ */
+/* FIXME we don't want globals here, but maybe ok? */
+#ifdef _REENTRANT
+static ei_mutex_t *ei_gethost_sem = NULL;
+#endif /* _REENTRANT */
+static int ei_resolve_initialized = 0;
+#ifndef __WIN32__
+int h_errno;
+#endif
+
+#ifdef DEBUG
+#define DEBUGF(X) fprintf X
+#else
+#define DEBUGF(X) /* Nothing */
+#endif
+
+#ifdef VXWORKS
+/* FIXME problem for threaded ? */
+static struct hostent *(*sens_gethostbyname)(const char *name,
+ char *, int) = NULL;
+static struct hostent *(*sens_gethostbyaddr)(const char *addr,
+ char *, int) = NULL;
+#endif
+
+#ifdef VXWORKS
+static int verify_dns_configuration(void);
+#endif
+
+/*
+ * If we find SENS resolver, use the functions found there, i.e.
+ * resolvGetHostByName() and resolvGetHostByAddr(). Otherwise we use
+ * our own, which are just wrappers around hostGetByName() and
+ * hostGetByAddr(). Here we look up the functions.
+ */
+void ei_init_resolve(void)
+{
+
+#ifdef VXWORKS
+ void *sym;
+ SYM_TYPE symtype;
+
+ if (symFindByName(sysSymTbl,"resolvGetHostByName",
+ (char **)&sym,&symtype) == OK &&
+ verify_dns_configuration()) {
+ sens_gethostbyname = sym;
+ DEBUGF((stderr,"found SENS resolver - using it for gethostbyname()\n"));
+ if (symFindByName(sysSymTbl,"resolvGetHostByAddr",
+ (char **)&sym,&symtype) == OK) {
+ sens_gethostbyaddr = sym;
+ DEBUGF((stderr,"found SENS resolver - "
+ "using it for gethostbyaddr()\n"));
+ }
+ else {
+ DEBUGF((stderr,"SENS resolver not found - "
+ "using default gethostbyaddr()\n"));
+ }
+ }
+ else {
+ DEBUGF((stderr,"SENS resolver not found - "
+ "using default gethostbyname()\n"));
+ }
+#endif /* VXWORKS */
+
+#ifdef _REENTRANT
+ ei_gethost_sem = ei_mutex_create();
+#endif /* _REENTRANT */
+
+ ei_resolve_initialized = 1;
+}
+
+#ifdef VXWORKS
+/*
+** Function to verify the DNS configuration on VwXorks SENS.
+** Actually configures to a default value if unconfigured...
+*/
+static int verify_dns_configuration(void)
+{
+ /* FIXME problem for threaded ? */
+ static char resolv_params[sizeof(RESOLV_PARAMS_S)];
+ void (*rpg)(char *);
+ STATUS (*rps)(char *);
+ SYM_TYPE dummy;
+ int get_result, set_result;
+
+ get_result = symFindByName(sysSymTbl,"resolvParamsGet", (char **) &rpg, &dummy);
+ set_result = symFindByName(sysSymTbl,"resolvParamsSet", (char **) &rps, &dummy);
+
+ if (!(get_result == OK &&
+ set_result == OK))
+ return -1;
+ (*rpg)(resolv_params);
+ if (*resolv_params == '\0') {
+ /* It exists, but is not configured, ei_connect would fail
+ if we left it this way... The best we can do is to configure
+ it to use the local host database on the card, as a fallback */
+ *resolv_params = (char) 1;
+ fprintf(stderr,"Trying to fix up DNS configuration.\n");
+ if (((*rps)(resolv_params)) != OK)
+ return -1;
+ }
+ return 0;
+}
+
+#endif
+
+/*
+ * Copy the contents of one struct hostent to another, i.e. don't just
+ * copy the pointers, copy all the data and create new pointers, etc.
+ * User must provide a secondary buffer to which the host data can be copied.
+ *
+ * Returns 0 on success or -1 if buffer is too small for host data
+*/
+
+/* a couple of helpers
+ * align: increment buf until it is dword-aligned, reduce len by same amount.
+ * advance: increment buf by n bytes, reduce len by same amount .
+ */
+#define align_buf(buf,len) for (;(((unsigned)buf)&0x3); (buf)++, len--)
+#define advance_buf(buf,len,n) ((buf)+=(n),(len)-=(n))
+
+/* "and now the tricky part..." */
+static int copy_hostent(struct hostent *dest, const struct hostent *src, char *buffer, int buflen)
+{
+ char **pptr;
+ int len;
+ char **src_aliases = NULL;
+ char **src_addr_list = NULL;
+
+ /* fix initial buffer alignment */
+ align_buf(buffer, buflen);
+
+ /* copy the data into our buffer... */
+ /* first the easy ones! */
+ dest->h_length = src->h_length;
+ dest->h_addrtype = src->h_addrtype;
+
+ /* h_name */
+ dest->h_name = buffer;
+ len = strlen(src->h_name);
+ if (buflen < len+1) return -1;
+ memmove((char *)dest->h_name,src->h_name,len);
+ buffer[len] = (char)0;
+ advance_buf(buffer,buflen,len+1);
+
+ /* traverse alias list, collecting the pointers */
+ align_buf(buffer, buflen);
+ pptr = (char **)buffer;
+ dest->h_aliases = pptr; /* save head of pointer array */
+
+ src_aliases = src->h_aliases;
+
+ while(*(src_aliases)) {
+ if (buflen < sizeof(*pptr)) return -1;
+ *pptr = src_aliases;
+ advance_buf(buffer,buflen,sizeof(*pptr));
+ src_aliases++;
+ pptr++;
+ }
+ if (buflen < sizeof(*pptr)) return -1;
+ *pptr = NULL;
+ advance_buf(buffer,buflen,sizeof(*pptr));
+
+ /* go back to saved position & transfer the alias data */
+ pptr = dest->h_aliases;
+ while (*pptr) {
+ len = strlen(*pptr);
+ if (buflen < len+1) return -1;
+ memmove(buffer,*pptr,len); /* copy data to local buffer */
+ buffer[len] = (char)0;
+ *pptr = buffer; /* point to own copy now */
+ advance_buf(buffer,buflen,len+1);
+ pptr++;
+ }
+
+ /* traverse address list, collecting the pointers */
+ align_buf(buffer, buflen);
+ pptr = (char **)buffer;
+ dest->h_addr_list = pptr; /* save head of pointer array */
+
+ src_addr_list = src->h_addr_list;
+
+ while(*(src_addr_list)) {
+ if (buflen < sizeof(*pptr)) return -1;
+ *pptr = *src_addr_list;
+ advance_buf(buffer,buflen,sizeof(*pptr));
+ src_addr_list++;
+ pptr++;
+ }
+ if (buflen < sizeof(*pptr)) return -1;
+ *pptr = NULL;
+ advance_buf(buffer,buflen,sizeof(*pptr));
+
+ /* go back to saved position & transfer the addresses */
+ /* align_buf(buffer, buflen); */
+ pptr = dest->h_addr_list;
+ while (*pptr) {
+ len = src->h_length;
+ if (buflen < len+1) return -1;
+ memmove(buffer,*pptr,len); /* copy data to local buffer */
+ buffer[len]=(char)0; /* not sure if termination is necessary */
+ *pptr = buffer; /* point to own copy now */
+ advance_buf(buffer,buflen,len+1);
+ pptr++;
+ }
+
+ if (buflen < 0) return -1;
+ return 0;
+}
+
+/* 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
+ * buffers. It's not pretty but it works.
+ *
+ * name - name of host to look up
+ * hostp - user-supplied structure for returning host entry
+ * buffer - user-supplied buffer: storage for the copied host data
+ * buflen - length of user-supplied buffer
+ * h_errnop - buffer for return status
+ *
+ * Returns values as for gethostbyname(). Additionally, sets
+ * errno=ERANGE and returns NULL if buffer is too small for host data.
+ */
+
+static struct hostent *my_gethostbyname_r(const char *name,
+ struct hostent *hostp,
+ char *buffer,
+ int buflen,
+ int *h_errnop)
+{
+ struct hostent dest;
+ struct hostent *src;
+ struct hostent *rval = NULL;
+
+ /* FIXME this should have been done in 'erl'_init()? */
+ if (!ei_resolve_initialized) ei_init_resolve();
+
+#ifdef _REENTRANT
+ /* === BEGIN critical section === */
+ if (ei_mutex_lock(ei_gethost_sem,0) != 0) {
+ *h_errnop = NO_RECOVERY;
+ return NULL;
+ }
+#endif /* _REENTRANT */
+
+ /* lookup the data */
+ if ((src = ei_gethostbyname(name))) {
+ /* copy to caller's buffer */
+ if (!copy_hostent(&dest,src,buffer,buflen)) {
+ /* success */
+ *hostp = dest;
+ *h_errnop = 0;
+ rval = hostp;
+ }
+
+ else {
+ /* failure - buffer size */
+#ifdef __WIN32__
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+#else
+ errno = ERANGE;
+#endif
+ *h_errnop = 0;
+ }
+ }
+
+ else {
+ /* failure - lookup */
+#ifdef __WIN32__
+ *h_errnop = WSAGetLastError();
+#else
+ *h_errnop = h_errno;
+#endif
+ }
+
+#ifdef _REENTRANT
+ /* === END critical section === */
+ ei_mutex_unlock(ei_gethost_sem);
+#endif /* _REENTRANT */
+ return rval;
+}
+
+static struct hostent *my_gethostbyaddr_r(const char *addr,
+ int length,
+ int type,
+ struct hostent *hostp,
+ char *buffer,
+ int buflen,
+ int *h_errnop)
+{
+ struct hostent dest;
+ struct hostent *src;
+ struct hostent *rval = NULL;
+
+ /* FIXME this should have been done in 'erl'_init()? */
+ if (!ei_resolve_initialized) ei_init_resolve();
+
+#ifdef _REENTRANT
+ /* === BEGIN critical section === */
+ if (ei_mutex_lock(ei_gethost_sem,0) != 0) {
+ *h_errnop = NO_RECOVERY;
+ return NULL;
+ }
+#endif /* _REENTRANT */
+
+ /* lookup the data */
+ if ((src = ei_gethostbyaddr(addr,length,type))) {
+ /* copy to caller's buffer */
+ if (!copy_hostent(&dest,src,buffer,buflen)) {
+ /* success */
+ *hostp = dest;
+ *h_errnop = 0;
+ rval = hostp;
+ }
+
+ else {
+ /* failure - buffer size */
+#ifdef __WIN32__
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+#else
+ errno = ERANGE;
+#endif
+ *h_errnop = 0;
+ }
+ }
+
+ else {
+ /* failure - lookup */
+#ifdef __WIN32__
+ *h_errnop = WSAGetLastError();
+#else
+ *h_errnop = h_errno;
+#endif
+ }
+
+
+#ifdef _REENTRANT
+ /* === END critical section === */
+ ei_mutex_unlock(ei_gethost_sem);
+#endif /* _REENTRANT */
+ return rval;
+}
+
+
+#endif /* !HAVE_GETHOSTBYNAME_R */
+
+
+#ifdef __WIN32__
+struct hostent *ei_gethostbyname(const char *name)
+{
+ return gethostbyname(name);
+}
+
+struct hostent *ei_gethostbyaddr(const char *addr, int len, int type)
+{
+ return gethostbyaddr(addr, len, type);
+}
+
+#elif VXWORKS
+
+
+/* these are a couple of substitutes for the real thing when we run on
+ * stock vxworks (i.e. no sens).
+ *
+ * len and type are ignored, but we make up some reasonable values and
+ * insert them
+ */
+static struct hostent *my_gethostbyname(const char *name)
+{
+ /* FIXME problem for threaded ? */
+ static struct hostent h;
+ static char hostname[EI_MAXHOSTNAMELEN+1];
+ static char *aliases[1] = {NULL};
+ static char *addrp[2] = {NULL,NULL};
+ static unsigned long addr = 0;
+
+ strcpy(hostname,name);
+ if ((addr = (unsigned long)hostGetByName(hostname)) == ERROR) {
+ h_errno = HOST_NOT_FOUND;
+ return NULL;
+ }
+
+ h_errno = 0;
+ h.h_name = hostname;
+ h.h_aliases = aliases;
+ h.h_length = 4;
+ h.h_addrtype = AF_INET;
+ addrp[0] = (char *)&addr;
+ h.h_addr_list = addrp;
+
+ return &h;
+}
+
+static struct hostent *my_gethostbyaddr(const char *addr, int len, int type)
+{
+ /* FIXME problem for threaded ? */
+ static struct hostent h;
+ static char hostname[EI_MAXHOSTNAMELEN+1];
+ static char *aliases[1] = { NULL };
+ static unsigned long inaddr;
+ static char *addrp[2] = {(char *)&inaddr, NULL};
+
+ memmove(&inaddr,addr,sizeof(inaddr));
+
+ if ((hostGetByAddr(inaddr,hostname)) == ERROR) {
+ h_errno = HOST_NOT_FOUND;
+ return NULL;
+ }
+
+ h_errno = 0;
+ h.h_name = hostname;
+ h.h_aliases = aliases;
+ h.h_length = 4;
+ h.h_addrtype = AF_INET;
+ h.h_addr_list = addrp;
+
+ return &h;
+}
+
+/* use sens functions for these, if found. */
+struct hostent *ei_gethostbyname(const char *name)
+{
+ struct hostent *h = NULL;
+
+ if (!sens_gethostbyname) {
+ h = my_gethostbyname(name);
+ }
+ else {
+ /* FIXME problem for threaded ? */
+ static char buf[1024];
+ h = sens_gethostbyname(name,buf,1024);
+ }
+
+ return h;
+}
+
+struct hostent *ei_gethostbyaddr(const char *addr, int len, int type)
+{
+ struct hostent *h = NULL;
+
+ if (!sens_gethostbyaddr) {
+ h = my_gethostbyaddr(addr,len,type);
+ }
+ else {
+ /* FIXME problem for threaded ? */
+ static char buf[1024];
+ h = sens_gethostbyaddr(addr,buf,1024);
+ }
+
+ return h;
+}
+
+struct hostent *ei_gethostbyaddr_r(const char *addr,
+ int length,
+ int type,
+ struct hostent *hostp,
+ char *buffer,
+ int buflen,
+ int *h_errnop)
+{
+ struct hostent *h = NULL;
+
+ /* use own func if sens function not available */
+ if (!sens_gethostbyaddr) {
+ h = my_gethostbyaddr_r(addr,length,type,hostp,buffer,buflen,h_errnop);
+ }
+ else {
+ if (!(h = sens_gethostbyaddr(addr,buffer,buflen))) {
+ /* sens returns status via errno */
+ *h_errnop = errno;
+ }
+ else {
+ *hostp = *h;
+ *h_errnop = 0;
+ }
+ }
+
+ return h;
+}
+
+struct hostent *ei_gethostbyname_r(const char *name,
+ struct hostent *hostp,
+ char *buffer,
+ int buflen,
+ int *h_errnop)
+{
+ struct hostent *h = NULL;
+
+ /* use own func if sens function not available */
+ if (!sens_gethostbyname) {
+ h = my_gethostbyname_r(name,hostp,buffer,buflen,h_errnop);
+ }
+ else {
+ if (!(h = sens_gethostbyname(name,buffer,buflen))) {
+ /* sens returns status via errno */
+ *h_errnop = errno;
+ }
+ else {
+ *hostp = *h;
+ *h_errnop = 0;
+ }
+ }
+
+ return h;
+}
+
+#else /* unix of some kind */
+
+struct hostent *ei_gethostbyname(const char *name)
+{
+ return gethostbyname(name);
+}
+
+struct hostent *ei_gethostbyaddr(const char *addr, int len, int type)
+{
+ return gethostbyaddr(addr, len, type);
+}
+
+struct hostent *ei_gethostbyaddr_r(const char *addr,
+ int length,
+ int type,
+ struct hostent *hostp,
+ char *buffer,
+ int buflen,
+ int *h_errnop)
+{
+#if (EI_THREADS == false)
+ /* threads disabled, no need to call reentrant function */
+ return gethostbyaddr(addr, length, type);
+#else
+#ifndef HAVE_GETHOSTBYNAME_R
+ return my_gethostbyaddr_r(addr,length,type,hostp,buffer,buflen,h_errnop);
+#else
+#if (defined(__GLIBC__) || (__FreeBSD_version >= 602000))
+ struct hostent *result;
+
+ gethostbyaddr_r(addr, length, type, hostp, buffer, buflen, &result,
+ h_errnop);
+
+ return result;
+#else
+ return gethostbyaddr_r(addr,length,type,hostp,buffer,buflen,h_errnop);
+#endif
+#endif
+#endif
+}
+
+struct hostent *ei_gethostbyname_r(const char *name,
+ struct hostent *hostp,
+ char *buffer,
+ int buflen,
+ int *h_errnop)
+{
+#ifndef _REENTRANT
+ /* threads disabled, no need to call reentrant function */
+ return gethostbyname(name);
+#else
+#ifndef HAVE_GETHOSTBYNAME_R
+ return my_gethostbyname_r(name,hostp,buffer,buflen,h_errnop);
+#else
+#if (defined(__GLIBC__) || (__FreeBSD_version >= 602000))
+ struct hostent *result;
+
+ gethostbyname_r(name, hostp, buffer, buflen, &result, h_errnop);
+
+ return result;
+#else
+ return gethostbyname_r(name,hostp,buffer,buflen,h_errnop);
+#endif
+#endif
+#endif
+}
+
+#endif /* vxworks, win, unix */
+
diff --git a/lib/erl_interface/src/connect/ei_resolve.h b/lib/erl_interface/src/connect/ei_resolve.h
new file mode 100644
index 0000000000..4cb8aff338
--- /dev/null
+++ b/lib/erl_interface/src/connect/ei_resolve.h
@@ -0,0 +1,24 @@
+/*
+ * %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%
+ */
+#ifndef _EI_RESOLVE_H
+#define _EI_RESOLVE_H
+
+void ei_init_resolve(void);
+
+#endif /* _EI_RESOLVE_H */
diff --git a/lib/erl_interface/src/connect/eirecv.c b/lib/erl_interface/src/connect/eirecv.c
new file mode 100644
index 0000000000..51fc32d65c
--- /dev/null
+++ b/lib/erl_interface/src/connect/eirecv.c
@@ -0,0 +1,280 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#ifdef __WIN32__
+# include <winsock2.h>
+# include <windows.h>
+# include <winbase.h>
+#else /* Unix/VxWorks */
+# include <unistd.h>
+#endif
+
+/* common */
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "eidef.h"
+#include "eiext.h"
+#include "eirecv.h"
+#include "ei_portio.h"
+#include "ei_internal.h"
+#include "putget.h"
+#include "ei_trace.h"
+#include "show_msg.h"
+
+#include <errno.h>
+
+#define EIRECVBUF 2048 /* largest possible header is approx 1300 bytes */
+
+/* length (4), PASS_THOUGH (1), header, message */
+int
+ei_recv_internal (int fd,
+ char **mbufp, int *bufsz,
+ erlang_msg *msg, int *msglenp,
+ int staticbufp, unsigned ms)
+{
+ char header[EIRECVBUF];
+ char *s=header;
+ char *mbuf=*mbufp;
+ int len = 0;
+ int msglen = 0;
+ int bytesread = 0;
+ int remain;
+ int arity;
+ int version;
+ int index = 0;
+ int i = 0;
+ int res;
+ int show_this_msg = 0;
+
+ /* get length field */
+ if ((res = ei_read_fill_t(fd, header, 4, ms)) != 4)
+ {
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+ len = get32be(s);
+
+ /* got tick - respond and return */
+ if (!len) {
+ char tock[] = {0,0,0,0};
+ ei_write_fill_t(fd, tock, sizeof(tock), ms); /* Failure no problem */
+ *msglenp = 0;
+ return 0; /* maybe flag ERL_EAGAIN [sverkerw] */
+ }
+
+ /* turn off tracing on each receive. it will be turned back on if
+ * we receive a trace token.
+ */
+ ei_trace(-1,NULL);
+
+ /* read enough to get at least entire header */
+ bytesread = (len > EIRECVBUF ? EIRECVBUF : len);
+ if ((i = ei_read_fill_t(fd,header,bytesread,ms)) != bytesread) {
+ erl_errno = (i == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+
+ /* now decode header */
+ /* pass-through, version, control tuple header, control message type */
+ s = header;
+ index = 1;
+ if ((get8(s) != ERL_PASS_THROUGH)
+ || ei_decode_version(header,&index,&version)
+ || (version != ERL_VERSION_MAGIC)
+ || ei_decode_tuple_header(header,&index,&arity)
+ || ei_decode_long(header,&index,&msg->msgtype))
+ {
+ erl_errno = EIO; /* Maybe another code for decoding errors */
+ return -1;
+ }
+
+ switch (msg->msgtype) {
+ case ERL_SEND: /* { SEND, Cookie, ToPid } */
+ if (ei_tracelevel > 0) show_this_msg = 1;
+ if (ei_decode_atom(header,&index,msg->cookie)
+ || ei_decode_pid(header,&index,&msg->to))
+ {
+ erl_errno = EIO;
+ return -1;
+ }
+
+ break;
+
+ case ERL_REG_SEND: /* { REG_SEND, From, Cookie, ToName } */
+ if (ei_tracelevel > 0) show_this_msg = 1;
+ if (ei_decode_pid(header,&index,&msg->from)
+ || ei_decode_atom(header,&index,msg->cookie)
+ || ei_decode_atom(header,&index,msg->toname))
+ {
+ erl_errno = EIO;
+ return -1;
+ }
+
+ /* actual message is remaining part of headerbuf, plus any unread bytes */
+ break;
+
+ case ERL_LINK: /* { LINK, From, To } */
+ case ERL_UNLINK: /* { UNLINK, From, To } */
+ case ERL_GROUP_LEADER: /* { GROUP_LEADER, From, To } */
+ if (ei_tracelevel > 1) show_this_msg = 1;
+ if (ei_decode_pid(header,&index,&msg->from)
+ || ei_decode_pid(header,&index,&msg->to))
+ {
+ erl_errno = EIO;
+ return -1;
+ }
+
+ break;
+
+ case ERL_EXIT: /* { EXIT, From, To, Reason } */
+ case ERL_EXIT2: /* { EXIT2, From, To, Reason } */
+ if (ei_tracelevel > 1) show_this_msg = 1;
+ if (ei_decode_pid(header,&index,&msg->from)
+ || ei_decode_pid(header,&index,&msg->to))
+ {
+ erl_errno = EIO;
+ return -1;
+ }
+
+ break;
+
+ case ERL_SEND_TT: /* { SEND_TT, Cookie, ToPid, TraceToken } */
+ if (ei_tracelevel > 0) show_this_msg = 1;
+ if (ei_decode_atom(header,&index,msg->cookie)
+ || ei_decode_pid(header,&index,&msg->to)
+ || ei_decode_trace(header,&index,&msg->token))
+ {
+ erl_errno = EIO;
+ return -1;
+ }
+
+ ei_trace(1,&msg->token); /* turn on tracing */
+ break;
+
+ case ERL_REG_SEND_TT: /* { REG_SEND_TT, From, Cookie, ToName, TraceToken } */
+ if (ei_tracelevel > 0) show_this_msg = 1;
+ if (ei_decode_pid(header,&index,&msg->from)
+ || ei_decode_atom(header,&index,msg->cookie)
+ || ei_decode_atom(header,&index,msg->toname)
+ || ei_decode_trace(header,&index,&msg->token))
+ {
+ erl_errno = EIO;
+ return -1;
+ }
+
+ ei_trace(1,&msg->token); /* turn on tracing */
+ break;
+
+ case ERL_EXIT_TT: /* { EXIT_TT, From, To, TraceToken, Reason } */
+ case ERL_EXIT2_TT: /* { EXIT2_TT, From, To, TraceToken, Reason } */
+ if (ei_tracelevel > 1) show_this_msg = 1;
+ if (ei_decode_pid(header,&index,&msg->from)
+ || ei_decode_pid(header,&index,&msg->to)
+ || ei_decode_trace(header,&index,&msg->token))
+ {
+ erl_errno = EIO;
+ return -1;
+ }
+
+ ei_trace(1,&msg->token); /* turn on tracing */
+ break;
+
+ case ERL_NODE_LINK: /* { NODE_LINK } */
+ if (ei_tracelevel > 1) show_this_msg = 1;
+ break;
+
+ default:
+ /* unknown type, just put any remaining bytes into buffer */
+ break;
+ }
+
+ /* actual message is remaining part of headerbuf, plus any unread bytes */
+ msglen = len - index; /* message size (payload) */
+ remain = len - bytesread; /* bytes left to read */
+
+ /* if callers buffer is too small, we flush in the rest of the
+ * message and discard it, unless we know that we can reallocate
+ * the buffer in which case we do that and read the message.
+ */
+ if (msglen > *bufsz) {
+ if (staticbufp) {
+ int sz = EIRECVBUF;
+ /* flush in rest of packet */
+ while (remain > 0) {
+ if (remain < sz) sz = remain;
+ if ((i=ei_read_fill_t(fd,header,sz,ms)) <= 0) break;
+ remain -= i;
+ }
+ erl_errno = EMSGSIZE;
+ return -1;
+ }
+ else {
+ /* Dynamic buffer --- grow it. */
+#ifdef DEBUG
+ fprintf(stderr, "Growing buffer from %d bytes to %d bytes\n",
+ *bufsz, msglen);
+#endif
+ if ((mbuf = realloc(*mbufp, msglen)) == NULL)
+ {
+ erl_errno = ENOMEM;
+ return -1;
+ }
+
+ *mbufp = mbuf;
+ *bufsz = msglen;
+ }
+ }
+
+ /* move remaining bytes to callers buffer */
+ memmove(mbuf,header+index,bytesread-index);
+
+ /* let the caller know how big the message is in his buffer */
+ *msglenp = msglen;
+
+ /* read the rest of the message into callers buffer */
+ if (remain > 0) {
+ if ((i = ei_read_fill_t(fd,mbuf+bytesread-index,remain,ms)) != remain) {
+ *msglenp = bytesread-index+1; /* actual bytes in users buffer */
+ erl_errno = (i == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+ }
+
+ if (show_this_msg)
+ ei_show_recmsg(stderr,msg,mbuf);
+
+ /* the caller only sees "untraced" message types */
+ /* the trace token is buried in the message struct */
+ if (msg->msgtype > 10) msg->msgtype -= 10;
+
+ return msg->msgtype;
+}
+
+int ei_receive_encoded(int fd, char **mbufp, int *bufsz,
+ erlang_msg *msg, int *msglen)
+{
+ return ei_recv_internal(fd, mbufp, bufsz, msg, msglen, 0, 0);
+}
+
+int ei_receive_encoded_tmo(int fd, char **mbufp, int *bufsz, erlang_msg *msg, int *msglen, unsigned ms)
+{
+ return ei_recv_internal(fd, mbufp, bufsz, msg, msglen, 0, ms);
+}
+
diff --git a/lib/erl_interface/src/connect/eirecv.h b/lib/erl_interface/src/connect/eirecv.h
new file mode 100644
index 0000000000..b66eaeeb56
--- /dev/null
+++ b/lib/erl_interface/src/connect/eirecv.h
@@ -0,0 +1,26 @@
+/*
+ * %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%
+ */
+#ifndef _EIRECV_H
+#define _EIRECV_H
+
+/* Internal interface */
+int ei_recv_internal(int fd, char **mbufp, int *bufsz, erlang_msg *msg,
+ int *msglenp, int staticbufp, unsigned ms);
+
+#endif /* _EIRECV_H */
diff --git a/lib/erl_interface/src/connect/eisend.h b/lib/erl_interface/src/connect/eisend.h
new file mode 100644
index 0000000000..d83caf1352
--- /dev/null
+++ b/lib/erl_interface/src/connect/eisend.h
@@ -0,0 +1,41 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef _EISEND_H
+#define _EISEND_H
+
+/* FIXME strange, is this for debugging?! */
+#define EI_HAVE_TIMEOUT 1
+
+int ei_send_exit(int fd, const erlang_pid *from, const erlang_pid *to,
+ const char *msg);
+int ei_send_exit_tmo(int fd, const erlang_pid *from,
+ const erlang_pid *to,
+ const char *msg, unsigned ms);
+
+/* FIXME ei_send_*() functions not used */
+#if 0
+int ei_send_link(int fd, const erlang_pid *from, const erlang_pid *to);
+int ei_send_unlink(int fd, const erlang_pid *from, const erlang_pid *to);
+int ei_send_link_tmo(int fd, const erlang_pid *from,
+ const erlang_pid *to, unsigned ms);
+int ei_send_unlink_tmo(int fd, const erlang_pid *from,
+ const erlang_pid *to, unsigned ms);
+#endif /* Not used */
+
+#endif /* _EISEND_H */
diff --git a/lib/erl_interface/src/connect/send.c b/lib/erl_interface/src/connect/send.c
new file mode 100644
index 0000000000..cd832db4ea
--- /dev/null
+++ b/lib/erl_interface/src/connect/send.c
@@ -0,0 +1,125 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+
+#ifdef __WIN32__
+
+# include <winsock2.h>
+# include <windows.h>
+# include <winbase.h>
+
+#elif VXWORKS
+
+# include <sys/types.h>
+# include <unistd.h>
+# include <sysLib.h>
+# include <tickLib.h>
+
+#else /* unix */
+
+# include <sys/types.h>
+# include <unistd.h>
+# include <sys/uio.h>
+
+#endif
+
+#include <string.h>
+
+#include "eidef.h"
+#include "eiext.h"
+#include "eisend.h"
+#include "putget.h"
+#include "ei_connect_int.h"
+#include "ei_internal.h"
+#include "ei_trace.h"
+#include "ei_portio.h"
+#include "show_msg.h"
+
+
+int ei_send_encoded_tmo(int fd, const erlang_pid *to,
+ char *msg, int msglen, unsigned ms)
+{
+ char *s, header[1200]; /* see size calculation below */
+ erlang_trace *token = NULL;
+ int index = 5; /* reserve 5 bytes for control message */
+ int res;
+#ifdef HAVE_WRITEV
+ struct iovec v[2];
+#endif
+
+ /* are we tracing? */
+ /* check that he can receive trace tokens first */
+ if (ei_distversion(fd) > 0) token = ei_trace(0,NULL);
+
+ /* header = SEND, cookie, to max sizes: */
+ ei_encode_version(header,&index); /* 1 */
+ if (token) {
+ ei_encode_tuple_header(header,&index,4); /* 2 */
+ ei_encode_long(header,&index,ERL_SEND_TT); /* 2 */
+ } else {
+ ei_encode_tuple_header(header,&index,3);
+ ei_encode_long(header,&index,ERL_SEND);
+ }
+ ei_encode_atom(header,&index,ei_getfdcookie(fd)); /* 258 */
+ ei_encode_pid(header,&index,to); /* 268 */
+
+ if (token) ei_encode_trace(header,&index,token); /* 534 */
+
+ /* control message (precedes header actually) */
+ /* length = 1 ('p') + header len + message len */
+ s = header;
+ put32be(s, index + msglen - 4); /* 4 */
+ put8(s, ERL_PASS_THROUGH); /* 1 */
+ /*** sum: 1070 */
+
+ /* FIXME incorrect level */
+ if (ei_tracelevel > 0)
+ ei_show_sendmsg(stderr,header,msg);
+
+#ifdef HAVE_WRITEV
+
+ v[0].iov_base = (char *)header;
+ v[0].iov_len = index;
+ v[1].iov_base = (char *)msg;
+ v[1].iov_len = msglen;
+
+ if ((res = ei_writev_fill_t(fd,v,2,ms)) != index+msglen) {
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+
+#else /* !HAVE_WRITEV */
+
+ if ((res = ei_write_fill_t(fd,header,index,ms)) != index) {
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+ if ((res = ei_write_fill_t(fd,msg,msglen,ms)) != msglen) {
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+
+#endif /* !HAVE_WRITEV */
+
+ return 0;
+}
+
+int ei_send_encoded(int fd, const erlang_pid *to, char *msg, int msglen)
+{
+ return ei_send_encoded_tmo(fd, to, msg, msglen, 0);
+}
diff --git a/lib/erl_interface/src/connect/send_exit.c b/lib/erl_interface/src/connect/send_exit.c
new file mode 100644
index 0000000000..098797c96d
--- /dev/null
+++ b/lib/erl_interface/src/connect/send_exit.c
@@ -0,0 +1,101 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#ifdef __WIN32__
+# include <winsock2.h>
+# include <windows.h>
+# include <winbase.h>
+#else /* Unix/VxWorks */
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "eisend.h"
+#include "ei_connect_int.h"
+#include "ei_trace.h"
+#include "ei_internal.h"
+#include "putget.h"
+#include "ei_portio.h"
+#include "show_msg.h"
+
+/* use this to break a link */
+int ei_send_exit(int fd, const erlang_pid *from,
+ const erlang_pid *to, const char *reason)
+{
+ return ei_send_exit_tmo(fd,from,to,reason,0);
+}
+
+
+int ei_send_exit_tmo(int fd, const erlang_pid *from, const erlang_pid *to,
+ const char *reason, unsigned ms)
+{
+ char sbuf[EISMALLBUF];
+ erlang_trace *token = NULL;
+ char *dbuf = NULL;
+ char *msgbuf;
+ char *s;
+ int index = 0;
+ int len = strlen(reason) + 1080; /* see below */
+
+ if (len > EISMALLBUF)
+ if (!(dbuf = malloc(len)))
+ return -1;
+ msgbuf = (dbuf ? dbuf : sbuf);
+
+
+ /* are we tracing? */
+ /* check that he can receive trace tokens first */
+ if (ei_distversion(fd) > 0) token = ei_trace(0,NULL);
+
+ index = 5; /* max sizes: */
+ ei_encode_version(msgbuf,&index); /* 1 */
+ if (token) {
+ ei_encode_tuple_header(msgbuf,&index,5); /* 2 */
+ ei_encode_long(msgbuf,&index,ERL_EXIT_TT); /* 2 */
+ }
+ else {
+ ei_encode_tuple_header(msgbuf,&index,4);
+ ei_encode_long(msgbuf,&index,ERL_EXIT);
+ }
+ ei_encode_pid(msgbuf,&index,from); /* 268 */
+ ei_encode_pid(msgbuf,&index,to); /* 268 */
+
+ if (token) ei_encode_trace(msgbuf,&index,token); /* 534 */
+
+ /* Reason */
+ ei_encode_string(msgbuf,&index,reason); /* len */
+
+ /* 5 byte header missing */
+ s = msgbuf;
+ put32be(s, index - 4); /* 4 */
+ put8(s, ERL_PASS_THROUGH); /* 1 */
+ /*** sum: len + 1080 */
+ /* FIXME incorrect level */
+ if (ei_tracelevel > 1)
+ ei_show_sendmsg(stderr,msgbuf,NULL);
+
+ ei_write_fill_t(fd,msgbuf,index,ms);
+ /* FIXME ignore timeout etc? erl_errno?! */
+
+ if (dbuf) free(dbuf);
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/connect/send_reg.c b/lib/erl_interface/src/connect/send_reg.c
new file mode 100644
index 0000000000..8f0e40309c
--- /dev/null
+++ b/lib/erl_interface/src/connect/send_reg.c
@@ -0,0 +1,122 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+
+#elif VXWORKS
+#include <sys/types.h>
+#include <unistd.h>
+
+#else /* unix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#endif
+
+#include <stdio.h>
+
+#include "eidef.h"
+#include "eiext.h"
+#include "eisend.h"
+#include "putget.h"
+#include "ei_connect_int.h"
+#include "ei_internal.h"
+#include "ei_trace.h"
+#include "ei_portio.h"
+#include "show_msg.h"
+
+int ei_send_reg_encoded_tmo(int fd, const erlang_pid *from,
+ const char *to, char *msg, int msglen,
+ unsigned ms)
+{
+ char *s, header[1400]; /* see size calculation below */
+ erlang_trace *token = NULL;
+ int index = 5; /* reserve 5 bytes for control message */
+ int res;
+
+#ifdef HAVE_WRITEV
+ struct iovec v[2];
+#endif
+
+ /* are we tracing? */
+ /* check that he can receive trace tokens first */
+ if (ei_distversion(fd) > 0)
+ token = ei_trace(0,NULL);
+
+ /* header = REG_SEND, from, cookie, toname max sizes: */
+ ei_encode_version(header,&index); /* 1 */
+ if (token) {
+ ei_encode_tuple_header(header,&index,5); /* 2 */
+ ei_encode_long(header,&index,ERL_REG_SEND_TT); /* 2 */
+ } else {
+ ei_encode_tuple_header(header,&index,4);
+ ei_encode_long(header,&index,ERL_REG_SEND);
+ }
+ ei_encode_pid(header, &index, from); /* 268 */
+ ei_encode_atom(header, &index, ei_getfdcookie(fd)); /* 258 */
+ ei_encode_atom(header, &index, to); /* 268 */
+
+ if (token) ei_encode_trace(header,&index,token); /* 534 */
+
+ /* control message (precedes header actually) */
+ /* length = 1 ('p') + header len + message len */
+ s = header;
+ put32be(s, index + msglen - 4); /* 4 */
+ put8(s, ERL_PASS_THROUGH); /* 1 */
+ /*** sum: 1336 */
+ /* FIXME incorrect level.... */
+ if (ei_tracelevel > 0)
+ ei_show_sendmsg(stderr,header,msg);
+
+#ifdef HAVE_WRITEV
+
+ v[0].iov_base = (char *)header;
+ v[0].iov_len = index;
+ v[1].iov_base = (char *)msg;
+ v[1].iov_len = msglen;
+
+ if ((res = ei_writev_fill_t(fd,v,2,ms)) != index+msglen) {
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+#else
+
+ /* no writev() */
+ if ((res = ei_write_fill_t(fd,header,index,ms)) != index) {
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+ if ((res = ei_write_fill_t(fd,msg,msglen,ms)) != msglen) {
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+
+int ei_send_reg_encoded(int fd, const erlang_pid *from, const char *to,
+ char *msg, int msglen)
+{
+ return ei_send_reg_encoded_tmo(fd, from, to, msg, msglen, 0);
+}
+
diff --git a/lib/erl_interface/src/decode/decode_atom.c b/lib/erl_interface/src/decode/decode_atom.c
new file mode 100644
index 0000000000..b247bd4e17
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_atom.c
@@ -0,0 +1,42 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_decode_atom(const char *buf, int *index, char *p)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ int len;
+
+ if (get8(s) != ERL_ATOM_EXT) return -1;
+
+ len = get16be(s);
+
+ if (p) {
+ memmove(p,s,len);
+ p[len] = (char)0;
+ }
+ s += len;
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/decode/decode_big.c b/lib/erl_interface/src/decode/decode_big.c
new file mode 100644
index 0000000000..efe9c6e5d9
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_big.c
@@ -0,0 +1,331 @@
+/*
+ * %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%
+ */
+#include <string.h>
+#include <stdlib.h>
+
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_decode_big(const char *buf, int *index, erlang_big *b) {
+ unsigned int digit_bytes;
+ const unsigned char *s = (unsigned char*) buf + *index;
+ const unsigned char *s0 = s;
+
+ switch ( get8(s) ) {
+ case ERL_SMALL_BIG_EXT:
+ digit_bytes = get8(s);
+ break;
+ case ERL_LARGE_BIG_EXT:
+ digit_bytes = get32be(s);
+ break;
+ default:
+ return -1;
+ }
+ if ( b ) {
+ unsigned short *dt = b->digits;
+ unsigned int n = (digit_bytes+1)/2;
+ int i;
+
+ if ( digit_bytes != b->arity ) {
+ return -1;
+ }
+
+ b->is_neg = get8(s);
+
+ for (i = 0; i < n; ++i) {
+ dt[i] = s[i*2];
+ if ((i*2 + 1) < digit_bytes) {
+ dt[i] |= ((unsigned short) s[(i*2)+1]) << 8;
+ }
+ }
+ } else {
+ s++; /* skip sign byte */
+ }
+
+ s += digit_bytes;
+
+ *index += s-s0;
+
+ return 0;
+}
+
+erlang_big *ei_alloc_big(unsigned int digit_bytes) {
+ erlang_big *b;
+ unsigned int n = (digit_bytes+1)/2;
+
+ if ( (b = malloc(sizeof(erlang_big))) == NULL) return NULL;
+ memset(b,(char)0,sizeof(erlang_big));
+ if ( (b->digits = malloc(2*n)) == NULL) {
+ free(b);
+ return 0;
+ }
+
+ b->arity = digit_bytes;
+ memset(b->digits,(char)0, 2*n);
+ return b;
+}
+
+void ei_free_big(erlang_big *b)
+{
+ if (!b) return;
+ if (b->digits) free(b->digits);
+ free(b);
+}
+
+/* big compare functions */
+
+typedef unsigned short Uint16;
+typedef unsigned int Uint;
+
+typedef Uint16 digit_t;
+typedef Uint dsize_t;
+
+static int I_comp(digit_t *x, dsize_t xl, digit_t *y, dsize_t yl)
+{
+ if (xl<yl) {
+ return -1;
+ } else if (xl>yl) {
+ return 1;
+ } else {
+ if ( x == y ) return 0;
+ x += (xl-1);
+ y += (yl-1);
+ while( (xl>0) && (*x==*y) ) {
+ x--;
+ y--;
+ xl--;
+ }
+ if ( xl == 0 ) return 0;
+ return ( *x < *y ) ? -1 : 1;
+ }
+}
+
+int ei_big_comp(erlang_big *x, erlang_big *y)
+{
+ if ( x->is_neg == y->is_neg ) {
+ int c = I_comp(x->digits,(x->arity+1)/2,y->digits,(y->arity+1)/2);
+ if ( x->is_neg )
+ return -c;
+ else
+ return c;
+ } else {
+ return x->is_neg ? -1 : 1;
+ }
+}
+
+#define D_EXP 16
+#define D_BASE (1<<D_EXP)
+
+#define D_DECIMAL_EXP 4 /* 10^4 == 10000 */
+#define D_DECIMAL_BASE 10000 /* Max decimal exponent in a digit */
+
+#define DLOW(x) ((digit_t)((x) & (D_BASE-1)))
+#define DHIGH(x) ((digit_t)((x) >> D_EXP))
+
+/*
+ * Handling of floating point exceptions.
+ */
+
+#if defined(VXWORKS) && CPU == PPC860
+#undef NO_FPE_SIGNALS
+#define NO_FPE_SIGNALS 1
+#undef INLINED_FP_CONVERSION
+#define INLINED_FP_CONVERSION 1
+#endif
+
+#ifdef USE_ISINF_ISNAN /* simulate finite() */
+# define finite(f) (!isinf(f) && !isnan(f))
+# define HAVE_FINITE
+#endif
+
+#ifdef NO_FPE_SIGNALS
+# define ERTS_FP_CHECK_INIT() do {} while (0)
+# define ERTS_FP_ERROR(f, Action) if (!finite(f)) { Action; } else {}
+# define ERTS_SAVE_FP_EXCEPTION()
+# define ERTS_RESTORE_FP_EXCEPTION()
+#else
+/* extern volatile int erl_fp_exception; */
+static volatile int erl_fp_exception;
+# define ERTS_FP_CHECK_INIT() do {erl_fp_exception = 0;} while (0)
+# if defined(__i386__) && defined(__GNUC__)
+/* extern void erts_restore_x87(void); */
+
+static void unmask_fpe(void)
+{
+ unsigned short cw;
+ __asm__ __volatile__("fstcw %0" : "=m"(cw));
+ cw &= ~(0x01|0x04|0x08); /* unmask IM, ZM, OM */
+ __asm__ __volatile__("fldcw %0" : : "m"(cw));
+}
+
+static void erts_restore_x87(void)
+{
+ __asm__ __volatile__("fninit");
+ unmask_fpe();
+}
+
+static int erts_check_x87(double f)
+{
+ __asm__ __volatile__("fwait" : "=m"(erl_fp_exception) : "m"(f));
+ if( !erl_fp_exception )
+ return 0;
+ erts_restore_x87();
+ return 1;
+}
+# define ERTS_FP_ERROR(f, Action) do { if( erts_check_x87((f)) ) { Action; } } while (0)
+# else
+# define ERTS_FP_ERROR(f, Action) if (erl_fp_exception) { Action; } else {}
+# endif
+# define ERTS_SAVE_FP_EXCEPTION() int old_erl_fp_exception = erl_fp_exception
+# define ERTS_RESTORE_FP_EXCEPTION() \
+ do {erl_fp_exception = old_erl_fp_exception;} while (0)
+#endif
+
+
+#ifdef INLINED_FP_CONVERSION
+static void join(unsigned d_split[4], unsigned *d)
+{
+ d[0] = (d_split[0] << 31) | /* Sign bit */
+ ((d_split[1] & 0x7FFU) << 20) | /* Exponent */
+ (d_split[2] & 0xFFFFFU); /* Mantissa MS bits */
+ d[1] = d_split[3]; /* Mantissa LS bits */
+}
+
+static int blength(unsigned long l)
+{
+ int i;
+ for(i = 0; l; ++i)
+ l >>= 1;
+ return i;
+}
+
+static int bblength(erlang_big *b)
+{
+ unsigned int wholebytes = (b->arity+1)/2;
+ digit_t *dp = b->digits;
+
+ while(wholebytes > 0 && dp[--wholebytes] == 0U)
+ ;
+
+ return (wholebytes * sizeof(digit_t) * 8) + blength(dp[wholebytes]);
+}
+
+static unsigned long bindex(erlang_big *b, int ndx) {
+ digit_t *dp = b->digits;
+ int skipdigits;
+ int dnum;
+
+ if (ndx < 0)
+ return 0;
+
+ skipdigits = ndx / (sizeof(digit_t) * 8);
+ dnum = ndx % (sizeof(digit_t) * 8);
+ return !!(dp[skipdigits] & (1UL << dnum));
+}
+
+
+#endif
+
+
+int ei_big_to_double(erlang_big *b, double *resp)
+{
+#ifdef INLINED_FP_CONVERSION
+ unsigned d_split[4];
+ unsigned *uresp = (unsigned *) resp;
+ unsigned len = bblength(b);
+ int i;
+ unsigned long msm = 0, lsm = 0;
+
+ /* OK, this is not the most efficient conversion in the world, especially
+ not the bit-by-bit copying to the mantissa.... Simple, working and
+ only for vxworks ppc860 where no sane person would use floating
+ point anyway, eh? /Patrik */
+
+ if (!len) {
+ memset(d_split,0,sizeof(d_split)); /* 0 */
+ } else {
+ --len;
+ if (len > 1023) { /* Infinite */
+ d_split[1] = 2047;
+ d_split[2] = d_split[3] = 0;
+ } else {
+ d_split[1] = 1023 + len;
+ --len; /* skip the implicit binary 1. */
+ for (i = 0; i < 20; ++i, --len) {
+ msm <<= 1;
+ msm |= bindex(b,len);
+ }
+ for (i = 0; i < 32; ++i, --len) {
+ lsm <<= 1;
+ lsm |= bindex(b,len);
+ }
+ d_split[2] = msm;
+ d_split[3] = lsm;
+ }
+ }
+ d_split[0] = (unsigned) !!(b->is_neg);
+ join(d_split,uresp);
+ return 0;
+#else
+ double d = 0.0;
+ double d_base = 1.0;
+
+ digit_t* s = (digit_t *)b->digits;
+ dsize_t xl = (b->arity + 1)/2;
+ short xsgn = b->is_neg;
+ ERTS_SAVE_FP_EXCEPTION();
+
+ ERTS_FP_CHECK_INIT();
+ while(xl--) {
+ digit_t ds = *s;
+ double d_next = ds * d_base + d;
+
+ ERTS_FP_ERROR(d_next, ERTS_RESTORE_FP_EXCEPTION(); {fprintf(stderr,"\r\n### fp exception ###\r\n"); return -1;});
+ s++;
+ d = d_next;
+ d_base *= D_BASE;
+ }
+
+ /*
+ * Note: The last multiplication in the loop could trigger an exception,
+ * which we will ignore because the result will never be used.
+ */
+
+ *resp = xsgn ? -d : d;
+ ERTS_FP_ERROR(*resp,;);
+ ERTS_RESTORE_FP_EXCEPTION();
+ return 0;
+#endif
+}
+
+int ei_small_to_big(int s, erlang_big *b)
+{
+ digit_t *d;
+ unsigned int n = (b->arity+1)/2;
+
+ if ( n < 2 ) return -1;
+
+ b->is_neg = ( s < 0 );
+ d = (digit_t *)b->digits;
+ d[0] = DLOW(s);
+ d[1] = DHIGH(s);
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/decode/decode_bignum.c b/lib/erl_interface/src/decode/decode_bignum.c
new file mode 100644
index 0000000000..f10052f9fe
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_bignum.c
@@ -0,0 +1,75 @@
+/*
+ * %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%
+ */
+
+#include "eidef.h"
+
+#if defined(HAVE_GMP_H) && defined(HAVE_LIBGMP)
+
+#include <gmp.h>
+
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+
+int ei_decode_bignum(const char *buf, int *index, mpz_t obj)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ int arity;
+ int sign;
+ unsigned long n;
+
+ switch (get8(s)) {
+ case ERL_SMALL_INTEGER_EXT:
+ n = get8(s);
+ mpz_set_ui(obj, n);
+ break;
+
+ case ERL_INTEGER_EXT:
+ n = get32be(s);
+ mpz_set_ui(obj, n);
+ break;
+
+ case ERL_SMALL_BIG_EXT:
+ arity = get8(s);
+ goto decode_bytes;
+
+ case ERL_LARGE_BIG_EXT:
+ arity = get32be(s);
+ decode_bytes:
+ sign = get8(s);
+ mpz_import(obj, arity, -1, 1, 0, 0, s);
+ s += arity;
+ if (sign) {
+ mpz_neg(obj, obj);
+ }
+
+ break;
+
+ default:
+ return -1;
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
+
+#endif /* HAVE_GMP_H && HAVE_LIBGMP */
diff --git a/lib/erl_interface/src/decode/decode_binary.c b/lib/erl_interface/src/decode/decode_binary.c
new file mode 100644
index 0000000000..713e621e60
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_binary.c
@@ -0,0 +1,42 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_decode_binary(const char *buf, int *index, void *p, long *lenp)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ long len;
+
+ if (get8(s) != ERL_BINARY_EXT) return -1;
+
+ len = get32be(s);
+ if (p) memmove(p,s,len);
+ s += len;
+
+ if (lenp) *lenp = len;
+ *index += s-s0;
+
+ return 0;
+}
+
+
diff --git a/lib/erl_interface/src/decode/decode_boolean.c b/lib/erl_interface/src/decode/decode_boolean.c
new file mode 100644
index 0000000000..9fd09c63f1
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_boolean.c
@@ -0,0 +1,57 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+/* c non-zero -> erlang "true" atom, otherwise "false" */
+int ei_decode_boolean(const char *buf, int *index, int *p)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ int len;
+ int t;
+
+ if (get8(s) != ERL_ATOM_EXT) return -1;
+
+ len = get16be(s);
+
+ switch (len) {
+ case 4:
+ /* typecast makes ansi happy */
+ if (strncmp((char*)s,"true",4)) return -1;
+ t = 1;
+ break;
+
+ case 5:
+ if (strncmp((char*)s,"false",5)) return -1;
+ t = 0;
+ break;
+
+ default:
+ return -1;
+ }
+
+ s += len;
+ if (p) *p = t;
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/decode/decode_char.c b/lib/erl_interface/src/decode/decode_char.c
new file mode 100644
index 0000000000..0f9b3f6cff
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_char.c
@@ -0,0 +1,69 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_decode_char(const char *buf, int *index, char *p)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ long n;
+ int arity;
+
+ switch (get8(s)) {
+ case ERL_SMALL_INTEGER_EXT:
+ n = get8(s);
+ break;
+
+ case ERL_INTEGER_EXT:
+ n = get32be(s);
+ if (n < 0 || n > 255)
+ return -1;
+ break;
+
+ case ERL_SMALL_BIG_EXT:
+ arity = get8(s);
+ goto decode_big;
+ case ERL_LARGE_BIG_EXT:
+ arity = get32be(s);
+ decode_big:
+ {
+ int sign = get8(s);
+ int i;
+
+ if (sign) return -1; /* Char is always > 0 */
+
+ n = get8(s); /* First byte is our value */
+
+ for (i = 1; i < arity; i++) {
+ if (*(s++) != 0) return -1; /* All but first byte have to be 0 */
+ }
+ }
+ break;
+
+ default:
+ return -1;
+ }
+
+ if (p) *p = n;
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/decode/decode_double.c b/lib/erl_interface/src/decode/decode_double.c
new file mode 100644
index 0000000000..66dbe474ec
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_double.c
@@ -0,0 +1,39 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <stdio.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+
+int ei_decode_double(const char *buf, int *index, double *p)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ double f;
+
+ if (get8(s) != ERL_FLOAT_EXT) return -1;
+
+ if (sscanf(s, "%lf", &f) != 1) return -1;
+
+ s += 31;
+ if (p) *p = f;
+ *index += s-s0;
+ return 0;
+}
diff --git a/lib/erl_interface/src/decode/decode_fun.c b/lib/erl_interface/src/decode/decode_fun.c
new file mode 100644
index 0000000000..64fb9e86d8
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_fun.c
@@ -0,0 +1,123 @@
+/*
+ * %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%
+ */
+#include <string.h>
+#include <stdlib.h>
+
+#include "eidef.h"
+#include "eiext.h"
+#include "ei_malloc.h"
+#include "decode_skip.h"
+#include "putget.h"
+
+int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ int i, ix, ix0, n;
+
+ switch (get8(s)) {
+ case ERL_FUN_EXT:
+ /* mark as old (R7 and older) external fun */
+ if (p != NULL) p->arity = -1;
+ /* first number of free vars (environment) */
+ n = get32be(s);
+ /* then the pid */
+ ix = 0;
+ if (ei_decode_pid(s, &ix, (p == NULL ? (erlang_pid*)NULL : &p->pid)) < 0)
+ return -1;
+ /* then the module (atom) */
+ if (ei_decode_atom(s, &ix, (p == NULL ? (char*)NULL : p->module)) < 0)
+ return -1;
+ /* then the index */
+ if (ei_decode_long(s, &ix, (p == NULL ? (long*)NULL : &p->index)) < 0)
+ return -1;
+ /* then the uniq */
+ if (ei_decode_long(s, &ix, (p == NULL ? (long*)NULL : &p->uniq)) < 0)
+ return -1;
+ /* finally the free vars */
+ ix0 = ix;
+ for (i = 0; i < n; ++i) {
+ if (ei_skip_term(s, &ix) < 0)
+ return -1;
+ }
+ if (p != NULL) {
+ p->n_free_vars = n;
+ p->free_var_len = ix - ix0;
+ p->free_vars = ei_malloc(ix - ix0);
+ if (!(p->free_vars)) return -1;
+ memcpy(p->free_vars, s + ix0, ix - ix0);
+ }
+ s += ix;
+ *index += s-s0;
+ return 0;
+ break;
+ case ERL_NEW_FUN_EXT:
+ /* first total size */
+ n = get32be(s);
+ /* then the arity */
+ i = get8(s);
+ if (p != NULL) p->arity = i;
+ /* then md5 */
+ if (p != NULL) memcpy(p->md5, s, 16);
+ s += 16;
+ /* then index */
+ i = get32be(s);
+ if (p != NULL) p->index = i;
+ /* then the number of free vars (environment) */
+ i = get32be(s);
+ if (p != NULL) p->n_free_vars = i;
+ /* then the module (atom) */
+ ix = 0;
+ if (ei_decode_atom(s, &ix, (p == NULL ? (char*)NULL : p->module)) < 0)
+ return -1;
+ /* then the old_index */
+ if (ei_decode_long(s, &ix, (p == NULL ? (long*)NULL : &p->old_index)) < 0)
+ return -1;
+ /* then the old_uniq */
+ if (ei_decode_long(s, &ix, (p == NULL ? (long*)NULL : &p->uniq)) < 0)
+ return -1;
+ /* the the pid */
+ if (ei_decode_pid(s, &ix, (p == NULL ? (erlang_pid*)NULL : &p->pid)) < 0)
+ return -1;
+ /* finally the free vars */
+ s += ix;
+ n = n - (s - s0) + 1;
+ if (n < 0) return -1;
+ if (p != NULL) {
+ p->free_var_len = n;
+ if (n > 0) {
+ p->free_vars = malloc(n);
+ if (!(p->free_vars)) return -1;
+ memcpy(p->free_vars, s, n);
+ }
+ }
+ s += n;
+ *index += s-s0;
+ return 0;
+ break;
+ default:
+ return -1;
+ }
+}
+
+void free_fun(erlang_fun* f)
+{
+ if (f->free_var_len > 0)
+ ei_free(f->free_vars);
+}
diff --git a/lib/erl_interface/src/decode/decode_intlist.c b/lib/erl_interface/src/decode/decode_intlist.c
new file mode 100644
index 0000000000..65552a4ed4
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_intlist.c
@@ -0,0 +1,82 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+/* since Erlang sends int-lists as either lists or strings, this
+ * function can be used when the caller needs an array but doesn't
+ * know which type to decode
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_decode_intlist(const char *buf, int *index, long *a, int *count)
+{
+ const unsigned char *s = (const unsigned char *)(buf + *index);
+ const unsigned char *s0 = s;
+ int idx;
+ int len;
+ int i;
+
+ switch (get8(s)) {
+ case ERL_STRING_EXT:
+ len = get16be(s);
+
+ /* transfer and cast chars one at a time into array */
+ if (a) {
+ for (i=0; i<len; i++) {
+ a[i] = (long)(s[i]);
+ }
+ }
+ if (count) *count = len;
+ s += len;
+ break;
+
+ case ERL_LIST_EXT:
+ len = get32be(s);
+ idx = 0;
+
+ if (a) {
+ for (i=0; i<len; i++) {
+ if (ei_decode_long((char*)s,&idx,a+i) < 0) {
+ if (count) *count = i;
+ return -1;
+ }
+ }
+ }
+ else {
+ for (i=0; i<len; i++) {
+ if (ei_decode_long((char*)s,&idx,NULL) < 0) {
+ if (count) *count = i;
+ return -1;
+ }
+ }
+ }
+
+ if (count) *count = len;
+ s += idx;
+ break;
+
+ default:
+ return -1;
+ }
+
+
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/decode/decode_list_header.c b/lib/erl_interface/src/decode/decode_list_header.c
new file mode 100644
index 0000000000..dda711f9fd
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_list_header.c
@@ -0,0 +1,45 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_decode_list_header(const char *buf, int *index, int *arity)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+
+ switch (get8(s)) {
+ case ERL_NIL_EXT:
+ if (arity) *arity = 0;
+ break;
+
+ case ERL_LIST_EXT:
+ if (arity) *arity = get32be(s);
+ else s+= 4;
+ break;
+
+ default:
+ return -1;
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/decode/decode_long.c b/lib/erl_interface/src/decode/decode_long.c
new file mode 100644
index 0000000000..b4138247e0
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_long.c
@@ -0,0 +1,86 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+#ifndef EI_64BIT
+int ei_decode_long(const char *buf, int *index, long *p)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ long n;
+ int arity;
+
+ switch (get8(s)) {
+ case ERL_SMALL_INTEGER_EXT:
+ n = get8(s);
+ break;
+
+ case ERL_INTEGER_EXT:
+ n = get32be(s);
+ break;
+
+ case ERL_SMALL_BIG_EXT:
+ arity = get8(s);
+ goto decode_big;
+
+ case ERL_LARGE_BIG_EXT:
+ arity = get32be(s);
+
+ decode_big:
+ {
+ int sign = get8(s);
+ int i;
+ unsigned long u = 0;
+
+ /* Little Endian, and n always positive, except for LONG_MIN */
+ for (i = 0; i < arity; i++) {
+ if (i < 4) {
+ u |= get8(s) << (i * 8);
+ } else if (get8(s) != 0) {
+ return -1; /* All but first byte have to be 0 */
+ }
+ }
+
+ /* check for overflow */
+ if (sign) {
+ if (u > 0x80000000UL) {
+ return -1;
+ }
+ n = -((long)u);
+ } else {
+ if (u > 0x7FFFFFFF) {
+ return -1;
+ }
+ n = (long)u;
+ }
+ }
+ break;
+
+ default:
+ return -1;
+ }
+
+ if (p) *p = n;
+ *index += s-s0;
+
+ return 0;
+}
+#endif /* !EI_64BIT */
diff --git a/lib/erl_interface/src/decode/decode_longlong.c b/lib/erl_interface/src/decode/decode_longlong.c
new file mode 100644
index 0000000000..8ec9f76995
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_longlong.c
@@ -0,0 +1,100 @@
+/*
+ * %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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+#ifdef EI_64BIT
+int ei_decode_long(const char *buf, int *index, long *p)
+{
+ return ei_decode_longlong(buf, index, (EI_LONGLONG *)p);
+}
+#endif
+
+#ifdef _MSC_VER
+#define MAX_TO_NEGATE 0x8000000000000000Ui64
+#define MAX_TO_NOT_NEGATE 0x7FFFFFFFFFFFFFFFUi64
+#else
+#define MAX_TO_NEGATE 0x8000000000000000ULL
+#define MAX_TO_NOT_NEGATE 0x7FFFFFFFFFFFFFFFULL
+#endif
+
+int ei_decode_longlong(const char *buf, int *index, EI_LONGLONG *p)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ EI_LONGLONG n;
+ int arity;
+
+ switch (get8(s)) {
+ case ERL_SMALL_INTEGER_EXT:
+ n = get8(s);
+ break;
+
+ case ERL_INTEGER_EXT:
+ n = get32be(s);
+ break;
+
+ case ERL_SMALL_BIG_EXT:
+ arity = get8(s);
+ goto decode_big;
+
+ case ERL_LARGE_BIG_EXT:
+ arity = get32be(s);
+
+ decode_big:
+ {
+ int sign = get8(s);
+ int i;
+ EI_ULONGLONG u = 0;
+
+ /* Little Endian, and n always positive, except for LONG_MIN */
+ for (i = 0; i < arity; i++) {
+ if (i < 8) {
+ /* Use ULONGLONG not to get a negative integer if > 127 */
+ u |= ((EI_ULONGLONG)get8(s)) << (i * 8);
+ } else if (get8(s) != 0) {
+ return -1; /* All but first byte have to be 0 */
+ }
+ }
+
+ /* check for overflow */
+ if (sign) {
+ if (u > MAX_TO_NEGATE) {
+ return -1;
+ }
+ n = -((EI_LONGLONG) u);
+ } else {
+ if (u > MAX_TO_NOT_NEGATE) {
+ return -1;
+ }
+ n = (EI_LONGLONG) u;
+ }
+ }
+ break;
+
+ default:
+ return -1;
+ }
+
+ if (p) *p = n;
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/decode/decode_pid.c b/lib/erl_interface/src/decode/decode_pid.c
new file mode 100644
index 0000000000..5f2aec3b44
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_pid.c
@@ -0,0 +1,54 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_decode_pid(const char *buf, int *index, erlang_pid *p)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ int len;
+
+ if (get8(s) != ERL_PID_EXT) return -1;
+
+ /* first the nodename */
+ if (get8(s) != ERL_ATOM_EXT) return -1;
+
+ len = get16be(s);
+
+ if (p) {
+ memmove(p->node, s, len);
+ p->node[len] = (char)0;
+ }
+ s += len;
+
+ /* now the numbers: num (4), serial (4), creation (1) */
+ if (p) {
+ p->num = get32be(s) & 0x7fff; /* 15 bits */
+ p->serial = get32be(s) & 0x1fff; /* 13 bits */
+ p->creation = get8(s) & 0x03; /* 2 bits */
+ }
+ else s+= 9;
+
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/decode/decode_port.c b/lib/erl_interface/src/decode/decode_port.c
new file mode 100644
index 0000000000..7fb7d8d414
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_port.c
@@ -0,0 +1,53 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_decode_port(const char *buf, int *index, erlang_port *p)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ int len;
+
+ if (get8(s) != ERL_PORT_EXT) return -1;
+
+ /* first the nodename */
+ if (get8(s) != ERL_ATOM_EXT) return -1;
+
+ len = get16be(s);
+
+ if (p) {
+ memmove(p->node, s, len);
+ p->node[len] = (char)0;
+ }
+ s += len;
+
+ /* now the numbers: num (4), creation (1) */
+ if (p) {
+ p->id = get32be(s) & 0x0fffffff /* 28 bits */;
+ p->creation = get8(s) & 0x03;
+ }
+ else s += 5;
+
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/decode/decode_ref.c b/lib/erl_interface/src/decode/decode_ref.c
new file mode 100644
index 0000000000..6fc2cd6533
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_ref.c
@@ -0,0 +1,94 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_decode_ref(const char *buf, int *index, erlang_ref *p)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ int count, len, i;
+
+ switch (get8(s)) {
+ case ERL_REFERENCE_EXT:
+
+ /* first the nodename */
+ if (get8(s) != ERL_ATOM_EXT) return -1;
+
+ len = get16be(s);
+
+ if (p) {
+ memmove(p->node, s, len);
+ p->node[len] = (char)0;
+ }
+ s += len;
+
+ /* now the numbers: num (4), creation (1) */
+ if (p) {
+ p->n[0] = get32be(s);
+ p->len = 1;
+ p->creation = get8(s) & 0x03;
+ }
+ else s += 5;
+
+ *index += s-s0;
+
+ return 0;
+ break;
+
+ case ERL_NEW_REFERENCE_EXT:
+ /* first the integer count */
+ count = get16be(s);
+ if (p) p->len = count;
+
+ /* then the nodename */
+ if (get8(s) != ERL_ATOM_EXT) return -1;
+ len = get16be(s);
+
+ if (p) {
+ memmove(p->node, s, len);
+ p->node[len] = (char)0;
+ }
+ s += len;
+
+ /* creation */
+ if (p) {
+ p->creation = get8(s) & 0x03;
+ }
+ else s += 1;
+
+ /* finally the id integers */
+ if (p) {
+ for (i = 0; (i<count) && (i<3); i++) {
+ p->n[i] = get32be(s);
+ }
+ }
+ else s += 4 * count;
+
+ *index += s-s0;
+
+ return 0;
+ break;
+
+ default:
+ return -1;
+ }
+}
diff --git a/lib/erl_interface/src/decode/decode_skip.c b/lib/erl_interface/src/decode/decode_skip.c
new file mode 100644
index 0000000000..2fc68a3601
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_skip.c
@@ -0,0 +1,90 @@
+/*
+ * %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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "decode_skip.h"
+
+int ei_skip_term(const char* buf, int* index)
+{
+ int i, n, ty;
+
+ /* ASSERT(ep != NULL); */
+
+ ei_get_type_internal(buf, index, &ty, &n);
+ switch (ty) {
+ case ERL_ATOM_EXT:
+ /* FIXME: what if some weird locale is in use? */
+ if (ei_decode_atom(buf, index, NULL) < 0) return -1;
+ break;
+ case ERL_PID_EXT:
+ if (ei_decode_pid(buf, index, NULL) < 0) return -1;
+ break;
+ case ERL_PORT_EXT:
+ if (ei_decode_port(buf, index, NULL) < 0) return -1;
+ break;
+ case ERL_NEW_REFERENCE_EXT:
+ case ERL_REFERENCE_EXT:
+ if (ei_decode_ref(buf, index, NULL) < 0) return -1;
+ break;
+ case ERL_NIL_EXT:
+ if (ei_decode_list_header(buf, index, &n) < 0) return -1;
+ break;
+ case ERL_LIST_EXT:
+ if (ei_decode_list_header(buf, index, &n) < 0) return -1;
+ for (i = 0; i < n; ++i)
+ ei_skip_term(buf, index);
+ if (ei_get_type_internal(buf, index, &ty, &n) < 0) return -1;
+ if (ty != ERL_NIL_EXT)
+ ei_skip_term(buf, index);
+ else
+ if (ei_decode_list_header(buf, index, &n) < 0) return -1;
+ break;
+ case ERL_STRING_EXT:
+ if (ei_decode_string(buf, index, NULL) < 0) return -1;
+ break;
+ case ERL_SMALL_TUPLE_EXT:
+ case ERL_LARGE_TUPLE_EXT:
+ if (ei_decode_tuple_header(buf, index, &n) < 0) return -1;
+ for (i = 0; i < n; ++i)
+ ei_skip_term(buf, index);
+ break;
+ case ERL_BINARY_EXT:
+ if (ei_decode_binary(buf, index, NULL, NULL) < 0)
+ return -1;
+ break;
+ case ERL_SMALL_INTEGER_EXT:
+ case ERL_INTEGER_EXT:
+ if (ei_decode_long(buf, index, NULL) < 0) return -1;
+ break;
+ case ERL_SMALL_BIG_EXT:
+ case ERL_LARGE_BIG_EXT:
+ if (ei_decode_big(buf, index, NULL) < 0) return -1;
+ break;
+ case ERL_FLOAT_EXT:
+ if (ei_decode_double(buf, index, NULL) < 0) return -1;
+ break;
+ case ERL_FUN_EXT:
+ if (ei_decode_fun(buf, index, NULL) < 0) return -1;
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/decode/decode_skip.h b/lib/erl_interface/src/decode/decode_skip.h
new file mode 100644
index 0000000000..b6c7b09fe4
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_skip.h
@@ -0,0 +1,27 @@
+/*
+ * %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%
+ */
+/*
+ * Function:
+ * ei_print_term to print out a binary coded term
+ */
+
+#ifndef _DECODE_SKIP_H
+#define _DECODE_SKIP_H
+
+#endif /* _DECODE_SKIP_H */
diff --git a/lib/erl_interface/src/decode/decode_string.c b/lib/erl_interface/src/decode/decode_string.c
new file mode 100644
index 0000000000..bcbdca0438
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_string.c
@@ -0,0 +1,85 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+/* FIXME fix or document that special requirements on
+ the in data.... */
+
+int ei_decode_string(const char *buf, int *index, char *p)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ int len;
+ int i;
+ int etype;
+
+ switch (get8(s)) {
+ case ERL_STRING_EXT:
+ len = get16be(s);
+
+ if (p) {
+ memmove(p,s,len);
+ p[len] = (char)0;
+ }
+ s += len;
+ break;
+
+ case ERL_LIST_EXT:
+ /* Really long strings are represented as lists of small integers.
+ * We don't know in advance if the whole list is small integers,
+ * but we decode as much as we can, exiting early if we run into a
+ * non-character in the list.
+ */
+ len = get32be(s);
+ if (p) {
+ for (i=0; i<len; i++) {
+ if ((etype = get8(s)) != ERL_SMALL_INTEGER_EXT) {
+ p[i] = (char)0;
+ return -1;
+ }
+ p[i] = get8(s);
+ }
+ p[i] = (char)0;
+ }
+ else {
+ for (i=0; i<len; i++) {
+ if ((etype = get8(s)) != ERL_SMALL_INTEGER_EXT) return -1;
+ s++;
+ }
+ }
+ /* Check NIL tail */
+ if ((etype = get8(s)) != ERL_NIL_EXT) return -1;
+ break;
+
+ case ERL_NIL_EXT:
+ if (p) p[0] = (char)0;
+ break;
+
+ default:
+ return -1;
+ }
+
+
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/decode/decode_trace.c b/lib/erl_interface/src/decode/decode_trace.c
new file mode 100644
index 0000000000..ebaa78e29e
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_trace.c
@@ -0,0 +1,43 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include "eidef.h"
+#include "putget.h"
+
+int ei_decode_trace(const char *buf, int *index, erlang_trace *p)
+{
+ int arity = 0;
+ int tindex = *index;
+
+ /* use a temporary index if any function should fail */
+
+ /* { Flags, Label, Serial, FromPid, Prev } */
+ if (ei_decode_tuple_header(buf, &tindex, &arity)
+ || (arity != 5)
+ || ei_decode_long(buf, &tindex, &p->flags)
+ || ei_decode_long(buf, &tindex, &p->label)
+ || ei_decode_long(buf, &tindex, &p->serial)
+ || ei_decode_pid( buf, &tindex, &p->from)
+ || ei_decode_long(buf, &tindex, &p->prev)) return -1;
+
+ /* index is updated by the functions we called */
+
+ *index = tindex;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/decode/decode_tuple_header.c b/lib/erl_interface/src/decode/decode_tuple_header.c
new file mode 100644
index 0000000000..c0ba14ea47
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_tuple_header.c
@@ -0,0 +1,47 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_decode_tuple_header(const char *buf, int *index, int *arity)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ int i;
+
+ switch ((i=get8(s))) {
+ case ERL_SMALL_TUPLE_EXT:
+ if (arity) *arity = get8(s);
+ else s++;
+ break;
+
+ case ERL_LARGE_TUPLE_EXT:
+ if (arity) *arity = get32be(s);
+ else s += 4;
+ break;
+
+ default:
+ return -1;
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/decode/decode_ulong.c b/lib/erl_interface/src/decode/decode_ulong.c
new file mode 100644
index 0000000000..dcf3703be7
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_ulong.c
@@ -0,0 +1,78 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+#ifndef EI_64BIT
+int ei_decode_ulong(const char *buf, int *index, unsigned long *p)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ unsigned long n;
+ long sn;
+ int arity;
+
+ switch (get8(s)) {
+ case ERL_SMALL_INTEGER_EXT:
+ n = get8(s);
+ break;
+
+ case ERL_INTEGER_EXT:
+ sn = get32be(s);
+ if (sn < 0) return -1;
+ n = (unsigned long)sn;
+ break;
+
+ case ERL_SMALL_BIG_EXT:
+ arity = get8(s);
+ goto decode_big;
+
+ case ERL_LARGE_BIG_EXT:
+ arity = get32be(s);
+
+ decode_big:
+ {
+ int sign = get8(s);
+ int i;
+ n = 0;
+
+ if (sign) return -1;
+
+ /* Little Endian, up to four bytes always fit into unsigned long */
+ for (i = 0; i < arity; i++) {
+ if (i < 4) {
+ n |= get8(s) << (i * 8);
+ } else if (get8(s) != 0) {
+ return -1; /* All but first byte have to be 0 */
+ }
+ }
+ }
+ break;
+
+ default:
+ return -1;
+ }
+
+ if (p) *p = (unsigned long)n;
+ *index += s-s0;
+
+ return 0;
+}
+#endif /* EI_64BIT */
diff --git a/lib/erl_interface/src/decode/decode_ulonglong.c b/lib/erl_interface/src/decode/decode_ulonglong.c
new file mode 100644
index 0000000000..17ecea848d
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_ulonglong.c
@@ -0,0 +1,83 @@
+/*
+ * %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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+#ifdef EI_64BIT
+int ei_decode_ulong(const char *buf, int *index, unsigned long *p)
+{
+ return ei_decode_ulonglong(buf, index, (EI_ULONGLONG *)p);
+}
+#endif
+
+int ei_decode_ulonglong(const char *buf, int *index, EI_ULONGLONG *p)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ EI_ULONGLONG n;
+ int arity;
+ int sn;
+
+ switch (get8(s)) {
+ case ERL_SMALL_INTEGER_EXT:
+ n = get8(s);
+ break;
+
+ case ERL_INTEGER_EXT:
+ sn = get32be(s);
+ if (sn < 0) return -1;
+ n = (EI_ULONGLONG)sn;
+ break;
+
+ case ERL_SMALL_BIG_EXT:
+ arity = get8(s);
+ goto decode_big;
+
+ case ERL_LARGE_BIG_EXT:
+ arity = get32be(s);
+
+ decode_big:
+ {
+ int sign = get8(s);
+ int i;
+ n = 0;
+
+ if (sign) return -1;
+
+ /* Little Endian, up to four bytes always fit into unsigned long */
+ for (i = 0; i < arity; i++) {
+ if (i < 8) {
+ n |= ((EI_ULONGLONG)get8(s)) << (i * 8);
+ } else if (get8(s) != 0) {
+ return -1; /* All but first byte have to be 0 */
+ }
+ }
+ }
+ break;
+
+ default:
+ return -1;
+ }
+
+ if (p) *p = n;
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/decode/decode_version.c b/lib/erl_interface/src/decode/decode_version.c
new file mode 100644
index 0000000000..124d7272f4
--- /dev/null
+++ b/lib/erl_interface/src/decode/decode_version.c
@@ -0,0 +1,38 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+/* remove version identifier from the start of the buffer */
+int ei_decode_version(const char *buf, int *index, int *version)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ int v;
+
+ v = get8(s);
+ if (version) *version = v;
+ if (v != ERL_VERSION_MAGIC)
+ return -1;
+
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/depend.mk b/lib/erl_interface/src/depend.mk
new file mode 100644
index 0000000000..af753046e5
--- /dev/null
+++ b/lib/erl_interface/src/depend.mk
@@ -0,0 +1,1133 @@
+# Generated dependency rules
+$(ST_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \
+ misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \
+ misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \
+ connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \
+ connect/ei_resolve.h epmd/ei_epmd.h
+$(ST_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \
+ misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h
+$(ST_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \
+ misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h
+$(ST_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
+ connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
+ misc/show_msg.h
+$(ST_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \
+ misc/ei_internal.h misc/putget.h misc/show_msg.h
+$(ST_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
+ connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
+ misc/show_msg.h
+$(ST_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h
+$(ST_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/ei_malloc.h decode/decode_skip.h misc/putget.h
+$(ST_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ decode/decode_skip.h
+$(ST_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/putget.h
+$(ST_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h
+$(ST_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/putget.h
+$(ST_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(ST_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h misc/ei_x_encode.h
+$(ST_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h misc/ei_x_encode.h
+$(ST_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \
+ misc/putget.h
+$(ST_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
+ misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
+$(ST_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
+ misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
+$(ST_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/ei_decode_term.h misc/putget.h
+$(ST_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/ei_malloc.h misc/ei_format.h
+$(ST_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \
+ misc/ei_malloc.h misc/ei_locking.h
+$(ST_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h
+$(ST_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h
+$(ST_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/ei_printterm.h misc/ei_malloc.h
+$(ST_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \
+ ../include/ei.h misc/ei_locking.h
+$(ST_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/ei_trace.h
+$(ST_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \
+ misc/ei_malloc.h
+$(ST_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h
+$(ST_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h misc/putget.h
+$(ST_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \
+ misc/ei_internal.h misc/show_msg.h
+$(ST_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h
+$(ST_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h
+$(ST_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h
+$(ST_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h
+$(ST_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h
+$(ST_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h
+$(ST_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h
+$(ST_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h
+$(ST_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h
+$(ST_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h
+$(ST_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h
+$(ST_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
+ connect/ei_connect_int.h
+$(ST_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
+ connect/ei_connect_int.h
+$(ST_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(ST_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h ../include/erl_interface.h
+$(ST_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \
+ legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h
+$(ST_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \
+ ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \
+ legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \
+ legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \
+ misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h
+$(ST_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \
+ ../include/erl_interface.h ../include/ei.h legacy/erl_error.h
+$(ST_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \
+ $(TARGET)/config.h connect/ei_resolve.h \
+ ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \
+ legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \
+ legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h
+$(ST_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \
+ misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \
+ legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \
+ legacy/erl_eterm.h legacy/portability.h
+$(ST_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \
+ ../include/ei.h legacy/erl_eterm.h legacy/portability.h \
+ legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h
+$(ST_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \
+ ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \
+ legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \
+ misc/ei_malloc.h
+$(ST_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \
+ ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \
+ legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \
+ legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h
+$(ST_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \
+ legacy/erl_timeout.h
+$(ST_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
+ ../include/erl_interface.h legacy/erl_connect.h
+$(ST_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/eirecv.h ../include/erl_interface.h
+$(ST_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
+ ../include/erl_interface.h legacy/erl_connect.h
+$(ST_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
+ ../include/erl_interface.h legacy/erl_connect.h
+
+$(MT_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \
+ misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \
+ misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \
+ connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \
+ connect/ei_resolve.h epmd/ei_epmd.h
+$(MT_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \
+ misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h
+$(MT_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \
+ misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h
+$(MT_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
+ connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
+ misc/show_msg.h
+$(MT_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \
+ misc/ei_internal.h misc/putget.h misc/show_msg.h
+$(MT_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
+ connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
+ misc/show_msg.h
+$(MT_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h
+$(MT_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/ei_malloc.h decode/decode_skip.h misc/putget.h
+$(MT_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ decode/decode_skip.h
+$(MT_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/putget.h
+$(MT_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h
+$(MT_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/putget.h
+$(MT_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MT_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h misc/ei_x_encode.h
+$(MT_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h misc/ei_x_encode.h
+$(MT_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \
+ misc/putget.h
+$(MT_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
+ misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
+$(MT_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
+ misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
+$(MT_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/ei_decode_term.h misc/putget.h
+$(MT_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/ei_malloc.h misc/ei_format.h
+$(MT_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \
+ misc/ei_malloc.h misc/ei_locking.h
+$(MT_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h
+$(MT_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h
+$(MT_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/ei_printterm.h misc/ei_malloc.h
+$(MT_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \
+ ../include/ei.h misc/ei_locking.h
+$(MT_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/ei_trace.h
+$(MT_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \
+ misc/ei_malloc.h
+$(MT_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h
+$(MT_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h misc/putget.h
+$(MT_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \
+ misc/ei_internal.h misc/show_msg.h
+$(MT_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h
+$(MT_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h
+$(MT_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h
+$(MT_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h
+$(MT_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h
+$(MT_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h
+$(MT_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h
+$(MT_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h
+$(MT_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h
+$(MT_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h
+$(MT_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h
+$(MT_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
+ connect/ei_connect_int.h
+$(MT_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
+ connect/ei_connect_int.h
+$(MT_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MT_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h ../include/erl_interface.h
+$(MT_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \
+ legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h
+$(MT_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \
+ ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \
+ legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \
+ legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \
+ misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h
+$(MT_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \
+ ../include/erl_interface.h ../include/ei.h legacy/erl_error.h
+$(MT_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \
+ $(TARGET)/config.h connect/ei_resolve.h \
+ ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \
+ legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \
+ legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h
+$(MT_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \
+ misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \
+ legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \
+ legacy/erl_eterm.h legacy/portability.h
+$(MT_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \
+ ../include/ei.h legacy/erl_eterm.h legacy/portability.h \
+ legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h
+$(MT_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \
+ ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \
+ legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \
+ misc/ei_malloc.h
+$(MT_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \
+ ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \
+ legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \
+ legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h
+$(MT_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \
+ legacy/erl_timeout.h
+$(MT_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
+ ../include/erl_interface.h legacy/erl_connect.h
+$(MT_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/eirecv.h ../include/erl_interface.h
+$(MT_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
+ ../include/erl_interface.h legacy/erl_connect.h
+$(MT_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
+ ../include/erl_interface.h legacy/erl_connect.h
+
+$(MD_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \
+ misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \
+ misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \
+ connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \
+ connect/ei_resolve.h epmd/ei_epmd.h
+$(MD_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \
+ misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h
+$(MD_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \
+ misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h
+$(MD_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
+ connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
+ misc/show_msg.h
+$(MD_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \
+ misc/ei_internal.h misc/putget.h misc/show_msg.h
+$(MD_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
+ connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
+ misc/show_msg.h
+$(MD_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h
+$(MD_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/ei_malloc.h decode/decode_skip.h misc/putget.h
+$(MD_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ decode/decode_skip.h
+$(MD_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/putget.h
+$(MD_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h
+$(MD_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/putget.h
+$(MD_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MD_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h misc/ei_x_encode.h
+$(MD_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h misc/ei_x_encode.h
+$(MD_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \
+ misc/putget.h
+$(MD_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
+ misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
+$(MD_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
+ misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
+$(MD_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/ei_decode_term.h misc/putget.h
+$(MD_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/ei_malloc.h misc/ei_format.h
+$(MD_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \
+ misc/ei_malloc.h misc/ei_locking.h
+$(MD_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h
+$(MD_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h
+$(MD_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/ei_printterm.h misc/ei_malloc.h
+$(MD_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \
+ ../include/ei.h misc/ei_locking.h
+$(MD_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/ei_trace.h
+$(MD_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \
+ misc/ei_malloc.h
+$(MD_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h
+$(MD_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h misc/putget.h
+$(MD_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \
+ misc/ei_internal.h misc/show_msg.h
+$(MD_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h
+$(MD_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h
+$(MD_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h
+$(MD_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h
+$(MD_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h
+$(MD_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h
+$(MD_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h
+$(MD_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h
+$(MD_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h
+$(MD_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h
+$(MD_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h
+$(MD_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
+ connect/ei_connect_int.h
+$(MD_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
+ connect/ei_connect_int.h
+$(MD_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MD_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h ../include/erl_interface.h
+$(MD_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \
+ legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h
+$(MD_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \
+ ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \
+ legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \
+ legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \
+ misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h
+$(MD_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \
+ ../include/erl_interface.h ../include/ei.h legacy/erl_error.h
+$(MD_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \
+ $(TARGET)/config.h connect/ei_resolve.h \
+ ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \
+ legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \
+ legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h
+$(MD_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \
+ misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \
+ legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \
+ legacy/erl_eterm.h legacy/portability.h
+$(MD_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \
+ ../include/ei.h legacy/erl_eterm.h legacy/portability.h \
+ legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h
+$(MD_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \
+ ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \
+ legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \
+ misc/ei_malloc.h
+$(MD_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \
+ ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \
+ legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \
+ legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h
+$(MD_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \
+ legacy/erl_timeout.h
+$(MD_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
+ ../include/erl_interface.h legacy/erl_connect.h
+$(MD_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/eirecv.h ../include/erl_interface.h
+$(MD_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
+ ../include/erl_interface.h legacy/erl_connect.h
+$(MD_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
+ ../include/erl_interface.h legacy/erl_connect.h
+
+$(MDD_OBJDIR)/ei_connect.o: connect/ei_connect.c $(TARGET)/config.h \
+ misc/eidef.h ../include/ei.h misc/eiext.h misc/ei_portio.h \
+ misc/ei_internal.h connect/ei_connect_int.h misc/ei_locking.h \
+ connect/eisend.h connect/eirecv.h misc/eimd5.h misc/putget.h \
+ connect/ei_resolve.h epmd/ei_epmd.h
+$(MDD_OBJDIR)/ei_resolve.o: connect/ei_resolve.c $(TARGET)/config.h \
+ misc/eidef.h ../include/ei.h connect/ei_resolve.h misc/ei_locking.h
+$(MDD_OBJDIR)/eirecv.o: connect/eirecv.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h connect/eirecv.h misc/ei_portio.h \
+ misc/ei_internal.h misc/putget.h misc/ei_trace.h misc/show_msg.h
+$(MDD_OBJDIR)/send.o: connect/send.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
+ connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
+ misc/show_msg.h
+$(MDD_OBJDIR)/send_exit.o: connect/send_exit.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/ei_connect_int.h misc/ei_trace.h \
+ misc/ei_internal.h misc/putget.h misc/show_msg.h
+$(MDD_OBJDIR)/send_reg.o: connect/send_reg.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h connect/eisend.h misc/putget.h \
+ connect/ei_connect_int.h misc/ei_internal.h misc/ei_trace.h \
+ misc/show_msg.h
+$(MDD_OBJDIR)/decode_atom.o: decode/decode_atom.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_big.o: decode/decode_big.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_bignum.o: decode/decode_bignum.c $(TARGET)/config.h
+$(MDD_OBJDIR)/decode_binary.o: decode/decode_binary.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_boolean.o: decode/decode_boolean.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_char.o: decode/decode_char.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_double.o: decode/decode_double.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_fun.o: decode/decode_fun.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/ei_malloc.h decode/decode_skip.h misc/putget.h
+$(MDD_OBJDIR)/decode_intlist.o: decode/decode_intlist.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_list_header.o: decode/decode_list_header.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_long.o: decode/decode_long.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_pid.o: decode/decode_pid.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_port.o: decode/decode_port.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_ref.o: decode/decode_ref.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_skip.o: decode/decode_skip.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ decode/decode_skip.h
+$(MDD_OBJDIR)/decode_string.o: decode/decode_string.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_trace.o: decode/decode_trace.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/putget.h
+$(MDD_OBJDIR)/decode_tuple_header.o: decode/decode_tuple_header.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_ulong.o: decode/decode_ulong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_version.o: decode/decode_version.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_longlong.o: decode/decode_longlong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/decode_ulonglong.o: decode/decode_ulonglong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/encode_atom.o: encode/encode_atom.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/encode_bignum.o: encode/encode_bignum.c $(TARGET)/config.h
+$(MDD_OBJDIR)/encode_binary.o: encode/encode_binary.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/encode_boolean.o: encode/encode_boolean.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/encode_char.o: encode/encode_char.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/encode_double.o: encode/encode_double.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/encode_fun.o: encode/encode_fun.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/encode_list_header.o: encode/encode_list_header.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/encode_long.o: encode/encode_long.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/encode_pid.o: encode/encode_pid.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/encode_port.o: encode/encode_port.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/encode_ref.o: encode/encode_ref.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/encode_string.o: encode/encode_string.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/encode_trace.o: encode/encode_trace.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/putget.h
+$(MDD_OBJDIR)/encode_tuple_header.o: encode/encode_tuple_header.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/encode_ulong.o: encode/encode_ulong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/encode_version.o: encode/encode_version.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h
+$(MDD_OBJDIR)/encode_longlong.o: encode/encode_longlong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h misc/ei_x_encode.h
+$(MDD_OBJDIR)/encode_ulonglong.o: encode/encode_ulonglong.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h misc/ei_x_encode.h
+$(MDD_OBJDIR)/epmd_port.o: epmd/epmd_port.c misc/ei_internal.h epmd/ei_epmd.h \
+ misc/putget.h
+$(MDD_OBJDIR)/epmd_publish.o: epmd/epmd_publish.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
+ misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
+$(MDD_OBJDIR)/epmd_unpublish.o: epmd/epmd_unpublish.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/ei_internal.h \
+ misc/putget.h ../include/erl_interface.h epmd/ei_epmd.h
+$(MDD_OBJDIR)/ei_decode_term.o: misc/ei_decode_term.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/ei_decode_term.h misc/putget.h
+$(MDD_OBJDIR)/ei_format.o: misc/ei_format.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/ei_malloc.h misc/ei_format.h
+$(MDD_OBJDIR)/ei_locking.o: misc/ei_locking.c $(TARGET)/config.h \
+ misc/ei_malloc.h misc/ei_locking.h
+$(MDD_OBJDIR)/ei_malloc.o: misc/ei_malloc.c misc/ei_malloc.h
+$(MDD_OBJDIR)/ei_portio.o: misc/ei_portio.c misc/ei_portio.h misc/ei_internal.h
+$(MDD_OBJDIR)/ei_printterm.o: misc/ei_printterm.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/ei_printterm.h misc/ei_malloc.h
+$(MDD_OBJDIR)/ei_pthreads.o: misc/ei_pthreads.c $(TARGET)/config.h \
+ ../include/ei.h misc/ei_locking.h
+$(MDD_OBJDIR)/ei_trace.o: misc/ei_trace.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/ei_trace.h
+$(MDD_OBJDIR)/ei_x_encode.o: misc/ei_x_encode.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/ei_x_encode.h \
+ misc/ei_malloc.h
+$(MDD_OBJDIR)/eimd5.o: misc/eimd5.c misc/eimd5.h
+$(MDD_OBJDIR)/get_type.o: misc/get_type.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h misc/putget.h
+$(MDD_OBJDIR)/show_msg.o: misc/show_msg.c misc/eidef.h $(TARGET)/config.h \
+ ../include/ei.h misc/eiext.h misc/putget.h misc/ei_printterm.h \
+ misc/ei_internal.h misc/show_msg.h
+$(MDD_OBJDIR)/ei_compat.o: misc/ei_compat.c ../include/ei.h misc/ei_internal.h
+$(MDD_OBJDIR)/hash_dohash.o: registry/hash_dohash.c registry/hash.h ../include/ei.h
+$(MDD_OBJDIR)/hash_foreach.o: registry/hash_foreach.c registry/hash.h ../include/ei.h
+$(MDD_OBJDIR)/hash_freetab.o: registry/hash_freetab.c registry/hash.h ../include/ei.h
+$(MDD_OBJDIR)/hash_insert.o: registry/hash_insert.c registry/hash.h ../include/ei.h
+$(MDD_OBJDIR)/hash_isprime.o: registry/hash_isprime.c registry/hash.h ../include/ei.h
+$(MDD_OBJDIR)/hash_lookup.o: registry/hash_lookup.c registry/hash.h ../include/ei.h
+$(MDD_OBJDIR)/hash_newtab.o: registry/hash_newtab.c registry/hash.h ../include/ei.h
+$(MDD_OBJDIR)/hash_remove.o: registry/hash_remove.c registry/hash.h ../include/ei.h
+$(MDD_OBJDIR)/hash_resize.o: registry/hash_resize.c registry/hash.h ../include/ei.h
+$(MDD_OBJDIR)/hash_rlookup.o: registry/hash_rlookup.c registry/hash.h ../include/ei.h
+$(MDD_OBJDIR)/reg_close.o: registry/reg_close.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_delete.o: registry/reg_delete.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_dirty.o: registry/reg_dirty.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_dump.o: registry/reg_dump.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
+ connect/ei_connect_int.h
+$(MDD_OBJDIR)/reg_free.o: registry/reg_free.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_get.o: registry/reg_get.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_getf.o: registry/reg_getf.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_geti.o: registry/reg_geti.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_getp.o: registry/reg_getp.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_gets.o: registry/reg_gets.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_make.o: registry/reg_make.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_open.o: registry/reg_open.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_purge.o: registry/reg_purge.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_resize.o: registry/reg_resize.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_restore.o: registry/reg_restore.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ registry/reg.h registry/hash.h connect/eisend.h connect/eirecv.h \
+ connect/ei_connect_int.h
+$(MDD_OBJDIR)/reg_set.o: registry/reg_set.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_setf.o: registry/reg_setf.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_seti.o: registry/reg_seti.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_setp.o: registry/reg_setp.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_sets.o: registry/reg_sets.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_stat.o: registry/reg_stat.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/reg_tabstat.o: registry/reg_tabstat.c registry/reg.h ../include/ei.h \
+ registry/hash.h
+$(MDD_OBJDIR)/decode_term.o: legacy/decode_term.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h ../include/erl_interface.h
+$(MDD_OBJDIR)/encode_term.o: legacy/encode_term.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ misc/putget.h misc/ei_x_encode.h ../include/erl_interface.h \
+ legacy/erl_marshal.h legacy/erl_eterm.h legacy/portability.h
+$(MDD_OBJDIR)/erl_connect.o: legacy/erl_connect.c $(TARGET)/config.h \
+ ../include/erl_interface.h ../include/ei.h legacy/erl_config.h \
+ legacy/erl_connect.h legacy/erl_eterm.h legacy/portability.h \
+ legacy/erl_malloc.h misc/putget.h connect/ei_connect_int.h \
+ misc/ei_locking.h epmd/ei_epmd.h misc/ei_internal.h
+$(MDD_OBJDIR)/erl_error.o: legacy/erl_error.c $(TARGET)/config.h \
+ ../include/erl_interface.h ../include/ei.h legacy/erl_error.h
+$(MDD_OBJDIR)/erl_eterm.o: legacy/erl_eterm.c misc/ei_locking.h \
+ $(TARGET)/config.h connect/ei_resolve.h \
+ ../include/erl_interface.h ../include/ei.h legacy/erl_eterm.h \
+ legacy/portability.h legacy/erl_malloc.h legacy/erl_marshal.h \
+ legacy/erl_error.h legacy/erl_internal.h misc/ei_internal.h
+$(MDD_OBJDIR)/erl_fix_alloc.o: legacy/erl_fix_alloc.c $(TARGET)/config.h \
+ misc/ei_locking.h ../include/erl_interface.h ../include/ei.h \
+ legacy/erl_error.h legacy/erl_malloc.h legacy/erl_fix_alloc.h \
+ legacy/erl_eterm.h legacy/portability.h
+$(MDD_OBJDIR)/erl_format.o: legacy/erl_format.c ../include/erl_interface.h \
+ ../include/ei.h legacy/erl_eterm.h legacy/portability.h \
+ legacy/erl_malloc.h legacy/erl_error.h legacy/erl_internal.h
+$(MDD_OBJDIR)/erl_malloc.o: legacy/erl_malloc.c ../include/erl_interface.h \
+ ../include/ei.h legacy/erl_fix_alloc.h legacy/erl_malloc.h \
+ legacy/erl_internal.h legacy/erl_eterm.h legacy/portability.h \
+ misc/ei_malloc.h
+$(MDD_OBJDIR)/erl_marshal.o: legacy/erl_marshal.c $(TARGET)/config.h \
+ ../include/erl_interface.h ../include/ei.h legacy/erl_marshal.h \
+ legacy/erl_eterm.h legacy/portability.h legacy/erl_malloc.h \
+ legacy/erl_error.h legacy/erl_internal.h misc/eiext.h misc/putget.h
+$(MDD_OBJDIR)/erl_timeout.o: legacy/erl_timeout.c $(TARGET)/config.h \
+ legacy/erl_timeout.h
+$(MDD_OBJDIR)/global_names.o: legacy/global_names.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
+ ../include/erl_interface.h legacy/erl_connect.h
+$(MDD_OBJDIR)/global_register.o: legacy/global_register.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/eirecv.h ../include/erl_interface.h
+$(MDD_OBJDIR)/global_unregister.o: legacy/global_unregister.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
+ ../include/erl_interface.h legacy/erl_connect.h
+$(MDD_OBJDIR)/global_whereis.o: legacy/global_whereis.c misc/eidef.h \
+ $(TARGET)/config.h ../include/ei.h misc/eiext.h \
+ connect/eisend.h connect/eirecv.h connect/ei_connect_int.h \
+ ../include/erl_interface.h legacy/erl_connect.h
+
diff --git a/lib/erl_interface/src/eidefs.mk.in b/lib/erl_interface/src/eidefs.mk.in
new file mode 100644
index 0000000000..05f61236c3
--- /dev/null
+++ b/lib/erl_interface/src/eidefs.mk.in
@@ -0,0 +1,31 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+#
+
+# ----------------------------------------------------------------------
+
+# Have the ei and erl_interface libs been compiled for threads?
+EI_THREADS=@EI_THREADS@
+
+# Threads flags
+THR_DEFS=@THR_DEFS@
+
+# Threads libs
+THR_LIBS=@THR_LIBS@
+
+# ----------------------------------------------------------------------
diff --git a/lib/erl_interface/src/encode/eicode.h b/lib/erl_interface/src/encode/eicode.h
new file mode 100644
index 0000000000..cf008b7fa9
--- /dev/null
+++ b/lib/erl_interface/src/encode/eicode.h
@@ -0,0 +1,69 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef _EICODE_H
+#define _EICODE_H
+
+/*
+ * The following functions are used to encode from c native types directly into
+ * Erlang external format. To use them, you need
+ *
+ * - a destination buffer
+ * - an index counter
+ * - some data
+ * - an idea of how you want to represent the data as an Erlang term.
+ *
+ * You can encode exactly one (1) term into the buffer if you are
+ * going to transmit it to Erlang. Do the following:
+ *
+ * 1. Set your index to 0
+ * 2. Encode the version into the buffer: ei_encode_version(buf,&index);
+ * The function has now advanced index so the next item can be encoded.
+ * 3. Encode your term:
+ *
+ * Encoding non-compound types (i.e. not lists or tuples) is
+ * straightforward. Just do it!
+ *
+ * Encoding tuples is done by first encoding the tuple header (it
+ * contains the arity) and then encoding the tuple elements in
+ * sequence.
+ *
+ * Encoding lists is done by first encoding the list header (it
+ * contains the arity) and then encoding the list elements in
+ * sequence, and finally encoding an empty list.
+ *
+ * After all this, the index counter will tell you how much buffer you
+ * used. If you really need to know in advance how big the buffer
+ * should be, go through the same steps but with a NULL buffer. No
+ * attempt will be made to modify the buffer, but index will be
+ * updated as though you really did encode something.
+ */
+
+/* encode the given object into buf[index] as 'type'. 0 is
+ * returned and index is updated to the position for the next item. if
+ * buf == NULL, no data is actually copied, but index is updated to
+ * indicate the number of bytes that would have been necessary.
+ */
+
+/* FIXME where do we put these..... */
+
+erlang_big *ei_alloc_big(int arity);
+void ei_free_big(erlang_big *b);
+
+
+#endif /* _EICODE_H */
diff --git a/lib/erl_interface/src/encode/encode_atom.c b/lib/erl_interface/src/encode/encode_atom.c
new file mode 100644
index 0000000000..69f2d1451c
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_atom.c
@@ -0,0 +1,51 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_encode_atom(char *buf, int *index, const char *p)
+{
+ return ei_encode_atom_len(buf, index, p, strlen(p));
+}
+
+int ei_encode_atom_len(char *buf, int *index, const char *p, int len)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+
+ /* This function is documented to truncate at MAXATOMLEN (256) */
+ if (len > MAXATOMLEN)
+ len = MAXATOMLEN;
+
+ if (!buf) s += 3;
+ else {
+ put8(s,ERL_ATOM_EXT);
+ put16be(s,len);
+
+ memmove(s,p,len); /* unterminated string */
+ }
+ s += len;
+
+ *index += s-s0;
+
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/encode/encode_big.c b/lib/erl_interface/src/encode/encode_big.c
new file mode 100644
index 0000000000..25abf424b7
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_big.c
@@ -0,0 +1,84 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 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%
+ */
+
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+#include "ei_x_encode.h"
+
+int ei_encode_big(char *buf, int *index, erlang_big* big) {
+ unsigned char *s = (unsigned char *)buf + *index;
+ unsigned char *s0 = s;
+ unsigned int digit_bytes = big->arity;
+ unsigned int n = (digit_bytes+1)/2;
+
+ if (digit_bytes < 256) {
+ if (buf) {
+ put8(s, ERL_SMALL_BIG_EXT);
+ put8(s, digit_bytes);
+ } else {
+ s += 2;
+ }
+ } else {
+ if (buf) {
+ put8(s, ERL_LARGE_BIG_EXT);
+ put32be(s, digit_bytes);
+ } else {
+ s += 5;
+ }
+ }
+
+ if (buf) {
+ int i;
+ unsigned char hi, lo;
+ unsigned short *dt = big->digits;
+ put8(s, big->is_neg);
+
+ for (i = 0; i < n; ++i) {
+
+ hi = (unsigned char) (dt[i] >> 8);
+ lo = (unsigned char) (dt[i]);
+
+ s[i*2] = lo;
+ if ((i*2 + 1) < digit_bytes) {
+ s[i*2 + 1] = hi;
+ }
+ }
+
+ } else {
+ s ++; /* skip sign bit */
+ }
+
+ s += digit_bytes;
+
+ *index += s-s0;
+
+ return 0;
+}
+
+int ei_x_encode_big(ei_x_buff* x, erlang_big* big) {
+ int i = x->index;
+
+ ei_encode_big(NULL, &i, big);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_big(x->buff, &x->index, big);
+}
+
diff --git a/lib/erl_interface/src/encode/encode_bignum.c b/lib/erl_interface/src/encode/encode_bignum.c
new file mode 100644
index 0000000000..6850cb86a6
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_bignum.c
@@ -0,0 +1,81 @@
+/*
+ * %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%
+ */
+
+#include "eidef.h"
+
+#if defined(HAVE_GMP_H) && defined(HAVE_LIBGMP)
+
+#include <gmp.h>
+
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+#include "ei_x_encode.h"
+
+int ei_encode_bignum(char *buf, int *index, mpz_t obj)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+ size_t count;
+ int mpz_sign = mpz_sgn(obj);
+
+ /*
+ * FIXME we could code into ERL_[SMALL_]INTEGER_EXT but to make
+ * this code simple for now we always code into ERL_SMALL_BIG_EXT
+ */
+
+ if (mpz_sign == 0) { /* Special case, bignum is zero */
+ if (!buf) s += 2;
+ else {
+ put8(s,ERL_SMALL_INTEGER_EXT);
+ put8(s,0);
+ }
+ } else {
+
+ if (!buf) {
+ int numb = 8; /* # bits in each external format limb */
+ s += (mpz_sizeinbase(obj, 2) + numb-1) / numb;
+ } else {
+ char *arityp;
+
+ put8(s,ERL_LARGE_BIG_EXT);
+ arityp = s; /* fill in later */
+ s += 4;
+ put8(s, mpz_sign == 1); /* save sign separately */
+ mpz_export(s, &count, -1, 1, 0, 0, obj);
+ s += count;
+ put32le(arityp, count);
+ }
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
+
+int ei_x_encode_bignum(ei_x_buff* x, mpz_t n)
+{
+ int i = x->index;
+ ei_encode_bignum(NULL, &i, n);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_bignum(x->buff, &x->index, n);
+}
+
+#endif /* HAVE_GMP_H && HAVE_LIBGMP */
diff --git a/lib/erl_interface/src/encode/encode_binary.c b/lib/erl_interface/src/encode/encode_binary.c
new file mode 100644
index 0000000000..67a4dc1219
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_binary.c
@@ -0,0 +1,41 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_encode_binary(char *buf, int *index, const void *p, long len)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+
+ if (!buf) s += 5;
+ else {
+ put8(s,ERL_BINARY_EXT);
+ put32be(s,len);
+ memmove(s,p,len);
+ }
+ s += len;
+
+ *index += s-s0;
+
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/encode/encode_boolean.c b/lib/erl_interface/src/encode/encode_boolean.c
new file mode 100644
index 0000000000..51a166bea5
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_boolean.c
@@ -0,0 +1,47 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_encode_boolean(char *buf, int *index, int p)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+ char *val;
+ int len;
+
+ val = p ? "true" : "false";
+ len = strlen(val);
+
+ if (!buf) s += 3;
+ else {
+ put8(s,ERL_ATOM_EXT);
+ put16be(s,len);
+
+ memmove(s,val,len); /* unterminated string */
+ }
+ s += len;
+
+ *index += s-s0;
+
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/encode/encode_char.c b/lib/erl_interface/src/encode/encode_char.c
new file mode 100644
index 0000000000..a7d27c5261
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_char.c
@@ -0,0 +1,38 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_encode_char(char *buf, int *index, char p)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+
+ if (!buf) s += 2;
+ else {
+ put8(s,ERL_SMALL_INTEGER_EXT);
+ put8(s,(p & 0xff));
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/encode/encode_double.c b/lib/erl_interface/src/encode/encode_double.c
new file mode 100644
index 0000000000..53f3d52ba6
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_double.c
@@ -0,0 +1,42 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <stdio.h>
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_encode_double(char *buf, int *index, double p)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+
+ if (!buf) s ++;
+ else {
+ put8(s,ERL_FLOAT_EXT);
+ memset(s, 0, 31);
+ sprintf(s, "%.20e", p);
+ }
+ s += 31;
+
+ *index += s-s0;
+
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/encode/encode_fun.c b/lib/erl_interface/src/encode/encode_fun.c
new file mode 100644
index 0000000000..54ee2083d6
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_fun.c
@@ -0,0 +1,82 @@
+/*
+ * %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%
+ */
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_encode_fun(char *buf, int *index, const erlang_fun *p)
+{
+ int ix = *index;
+
+ if (p->arity == -1) {
+ /* ERL_FUN_EXT */
+ if (buf != NULL) {
+ char* s = buf + ix;
+ put8(s, ERL_FUN_EXT);
+ put32be(s, p->n_free_vars);
+ }
+ ix += sizeof(char) + 4;
+ if (ei_encode_pid(buf, &ix, &p->pid) < 0)
+ return -1;
+ if (ei_encode_atom(buf, &ix, p->module) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->index) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->uniq) < 0)
+ return -1;
+ if (buf != NULL)
+ memcpy(buf + ix, p->free_vars, p->free_var_len);
+ ix += p->free_var_len;
+ } else {
+ char *size_p;
+ /* ERL_NEW_FUN_EXT */
+ if (buf != NULL) {
+ char* s = buf + ix;
+ put8(s, ERL_NEW_FUN_EXT);
+ size_p = s;
+ s += 4;
+ put8(s, p->arity);
+ memcpy(s, p->md5, sizeof(p->md5));
+ s += sizeof(p->md5);
+ put32be(s, p->index);
+ put32be(s, p->n_free_vars);
+ } else
+ size_p = NULL;
+ ix += 1 + 4 + 1 + sizeof(p->md5) + 4 + 4;
+ if (ei_encode_atom(buf, &ix, p->module) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->old_index) < 0)
+ return -1;
+ if (ei_encode_long(buf, &ix, p->uniq) < 0)
+ return -1;
+ if (ei_encode_pid(buf, &ix, &p->pid) < 0)
+ return -1;
+ if (buf != NULL)
+ memcpy(buf + ix, p->free_vars, p->free_var_len);
+ ix += p->free_var_len;
+ if (size_p != NULL) {
+ int sz = buf + ix - size_p;
+ put32be(size_p, sz);
+ }
+ }
+ *index = ix;
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/encode/encode_list_header.c b/lib/erl_interface/src/encode/encode_list_header.c
new file mode 100644
index 0000000000..27da70ae15
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_list_header.c
@@ -0,0 +1,45 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_encode_list_header(char *buf, int *index, int arity)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+
+ if (arity < 0) return -1;
+ else if (arity > 0) {
+ if (!buf) s += 5;
+ else {
+ put8(s,ERL_LIST_EXT);
+ put32be(s,arity);
+ }
+ }
+ else {
+ /* empty list */
+ if (!buf) s++;
+ else put8(s,ERL_NIL_EXT);
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/encode/encode_long.c b/lib/erl_interface/src/encode/encode_long.c
new file mode 100644
index 0000000000..d616bb6e47
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_long.c
@@ -0,0 +1,64 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+#define abs(p) (((p)<0) ? -(p) : p)
+
+/* long -> erl_integer */
+/* note that this is the only place where data is stored Little Endian */
+
+#ifndef EI_64BIT
+int ei_encode_long(char *buf, int *index, long p)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+
+ if ((p < 256) && (p >= 0)) {
+ if (!buf) s += 2;
+ else {
+ put8(s,ERL_SMALL_INTEGER_EXT);
+ put8(s,(p & 0xff));
+ }
+ }
+ else if ((p <= ERL_MAX) && (p >= ERL_MIN)) {
+ /* FIXME: Non optimal, could use (p <= LONG_MAX) && (p >= LONG_MIN)
+ and skip next case */
+ if (!buf) s += 5;
+ else {
+ put8(s,ERL_INTEGER_EXT);
+ put32be(s,p);
+ }
+ }
+ else {
+ if (!buf) s += 7;
+ else {
+ put8(s,ERL_SMALL_BIG_EXT);
+ put8(s,4); /* len = four bytes */
+ put8(s, p < 0); /* save sign separately */
+ put32le(s, abs(p)); /* OBS: Little Endian, and p now positive */
+ }
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
+#endif /* EI_64BIT */
diff --git a/lib/erl_interface/src/encode/encode_longlong.c b/lib/erl_interface/src/encode/encode_longlong.c
new file mode 100644
index 0000000000..aff24e2478
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_longlong.c
@@ -0,0 +1,103 @@
+/*
+ * %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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+#include "ei_x_encode.h"
+
+#define abs(p) (((p)<0) ? -(p) : p)
+
+/* long -> erl_integer */
+/* note that this is the only place where data is stored Little Endian */
+
+/*
+ * For some 64 bit operations on some operating systems code
+ * compiled with GNU cc depends on "libgcc" for some 64 bit
+ * operations missing in hardware (or because of gcc bugs).
+ * If user code was linked together with the ei lib
+ * using other linkers than GNU ld this may cause problems.
+ * We moved ei_x_encode_longlong() here from "ei_x_encode.c"
+ * to limit this problem to users that actually use the ei
+ * longlong operations, not all ei_x users.
+ */
+int ei_x_encode_longlong(ei_x_buff* x, EI_LONGLONG n)
+{
+ int i = x->index;
+ ei_encode_longlong(NULL, &i, n);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_longlong(x->buff, &x->index, n);
+}
+
+#ifdef EI_64BIT
+int ei_encode_long(char *buf, int *index, long p)
+{
+ return ei_encode_longlong(buf, index, p);
+}
+#endif
+
+int ei_encode_longlong(char *buf, int *index, EI_LONGLONG p)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+
+ if ((p < 256) && (p >= 0)) {
+ if (!buf) s += 2;
+ else {
+ put8(s,ERL_SMALL_INTEGER_EXT);
+ put8(s,(p & 0xff));
+ }
+ } else if ((p <= ERL_MAX) && (p >= ERL_MIN)) {
+ /* FIXME: Non optimal, could use (p <= LONG_MAX) && (p >= LONG_MIN)
+ and skip next case */
+ if (!buf) s += 5;
+ else {
+ put8(s,ERL_INTEGER_EXT);
+ put32be(s,p);
+ }
+ } else {
+ /* We know 28-64 bits needed, i.e four to eight bytes */
+ EI_ULONGLONG up = abs(p); /* FIXME name uabs(x) not to confuse with abs */
+ if (buf) {
+ char *arityp;
+ int arity = 0;
+
+ put8(s,ERL_SMALL_BIG_EXT);
+ arityp = s++; /* fill in later */
+ put8(s, p < 0); /* save sign separately */
+ while (up) {
+ *s++ = up & 0xff; /* take lowest byte */
+ up >>= 8; /* shift unsigned */
+ arity++;
+ }
+ put8(arityp,arity);
+ } else {
+ s += 3; /* Type, arity and sign */
+ while (up) {
+ s++; /* take lowest byte */
+ up >>= 8; /* shift unsigned */
+ }
+ }
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/encode/encode_pid.c b/lib/erl_interface/src/encode/encode_pid.c
new file mode 100644
index 0000000000..ee7f235c17
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_pid.c
@@ -0,0 +1,52 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_encode_pid(char *buf, int *index, const erlang_pid *p)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+ int len = strlen(p->node);
+
+ if (!buf) s += 13 + len;
+ else {
+ put8(s,ERL_PID_EXT);
+
+ /* first the nodename */
+ put8(s,ERL_ATOM_EXT);
+
+ put16be(s,len);
+
+ memmove(s, p->node, len);
+ s += len;
+
+ /* now the integers */
+ put32be(s,p->num & 0x7fff); /* 15 bits */
+ put32be(s,p->serial & 0x1fff); /* 13 bits */
+ put8(s,(p->creation & 0x03)); /* 2 bits */
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/encode/encode_port.c b/lib/erl_interface/src/encode/encode_port.c
new file mode 100644
index 0000000000..fbbb33182e
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_port.c
@@ -0,0 +1,51 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_encode_port(char *buf, int *index, const erlang_port *p)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+ int len = strlen(p->node);
+
+ if (!buf) s += 9 + len;
+ else {
+ put8(s,ERL_PORT_EXT);
+
+ /* first the nodename */
+ put8(s,ERL_ATOM_EXT);
+
+ put16be(s,len);
+
+ memmove(s, p->node, len);
+ s += len;
+
+ /* now the integers */
+ put32be(s,p->id & 0x0fffffff /* 28 bits */);
+ put8(s,(p->creation & 0x03));
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/encode/encode_ref.c b/lib/erl_interface/src/encode/encode_ref.c
new file mode 100644
index 0000000000..292b452864
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_ref.c
@@ -0,0 +1,59 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_encode_ref(char *buf, int *index, const erlang_ref *p)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+ int len = strlen(p->node);
+ int i;
+
+ /* Always encode as an extended reference; all participating parties
+ are now expected to be able to decode extended references. */
+ if (!buf) s += 1 + 2 + (3+len) + p->len*4 + 1;
+ else {
+ put8(s,ERL_NEW_REFERENCE_EXT);
+
+ /* first, number of integers */
+ put16be(s, p->len);
+
+ /* then the nodename */
+ put8(s,ERL_ATOM_EXT);
+
+ put16be(s,len);
+
+ memmove(s, p->node, len);
+ s += len;
+
+ /* now the integers */
+ put8(s,(p->creation & 0x03));
+ for (i = 0; i < p->len; i++)
+ put32be(s,p->n[i]);
+
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/encode/encode_string.c b/lib/erl_interface/src/encode/encode_string.c
new file mode 100644
index 0000000000..1d342cb605
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_string.c
@@ -0,0 +1,77 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+
+int ei_encode_string(char *buf, int *index, const char *p)
+{
+ return ei_encode_string_len(buf, index, p, strlen(p));
+}
+
+int ei_encode_string_len(char *buf, int *index, const char *p, int len)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+ int i;
+
+ if (len == 0) {
+
+ if (!buf) {
+ s += 1;
+ } else {
+ put8(s,ERL_NIL_EXT);
+ }
+
+ } else if (len <= 0xffff) {
+
+ if (!buf) {
+ s += 3;
+ } else {
+ put8(s,ERL_STRING_EXT);
+ put16be(s,len);
+ memmove(s,p,len); /* unterminated string */
+ }
+ s += len;
+
+ } else {
+
+ if (!buf) {
+ s += 5 + (2*len) + 1;
+ } else {
+ /* strings longer than 65535 are encoded as lists */
+ put8(s,ERL_LIST_EXT);
+ put32be(s,len);
+
+ for (i=0; i<len; i++) {
+ put8(s,ERL_SMALL_INTEGER_EXT);
+ put8(s,p[i]);
+ }
+ put8(s,ERL_NIL_EXT);
+ }
+
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/encode/encode_trace.c b/lib/erl_interface/src/encode/encode_trace.c
new file mode 100644
index 0000000000..de46f7fae8
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_trace.c
@@ -0,0 +1,36 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include "eidef.h"
+#include "putget.h"
+
+int ei_encode_trace(char *buf, int *index, const erlang_trace *p)
+{
+ /* { Flags, Label, Serial, FromPid, Prev } */
+ ei_encode_tuple_header(buf,index,5);
+ ei_encode_long(buf,index,p->flags);
+ ei_encode_long(buf,index,p->label);
+ ei_encode_long(buf,index,p->serial);
+ ei_encode_pid(buf,index,&p->from);
+ ei_encode_long(buf,index,p->prev);
+
+ /* index is updated by the functions we called */
+
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/encode/encode_tuple_header.c b/lib/erl_interface/src/encode/encode_tuple_header.c
new file mode 100644
index 0000000000..97a3d1f808
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_tuple_header.c
@@ -0,0 +1,49 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+int ei_encode_tuple_header(char *buf, int *index, int arity)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+
+ if (arity < 0) return -1;
+
+ if (arity <= 0xff) {
+ if (!buf) s += 2;
+ else {
+ put8(s,ERL_SMALL_TUPLE_EXT);
+ put8(s,arity);
+ }
+ }
+ else {
+ if (!buf) s += 5;
+ else {
+ put8(s,ERL_LARGE_TUPLE_EXT);
+ put32be(s,arity);
+ }
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/encode/encode_ulong.c b/lib/erl_interface/src/encode/encode_ulong.c
new file mode 100644
index 0000000000..c4ff34e493
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_ulong.c
@@ -0,0 +1,57 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+#ifndef EI_64BIT
+int ei_encode_ulong(char *buf, int *index, unsigned long p)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+
+ if (p > ERL_MAX) {
+ if (!buf) s += 7;
+ else {
+ put8(s,ERL_SMALL_BIG_EXT);
+ put8(s,4); /* len = four bytes */
+ put8(s, 0); /* save sign separately */
+ put32le(s,p); /* OBS: Little Endian, and p now positive */
+ }
+ }
+ else if ((p < 256) && (p >= 0)) {
+ if (!buf) s += 2;
+ else {
+ put8(s,ERL_SMALL_INTEGER_EXT);
+ put8(s,(p & 0xff));
+ }
+ }
+ else {
+ if (!buf) s += 5;
+ else {
+ put8(s,ERL_INTEGER_EXT);
+ put32be(s,p);
+ }
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
+#endif /* EI_64BIT */
diff --git a/lib/erl_interface/src/encode/encode_ulonglong.c b/lib/erl_interface/src/encode/encode_ulonglong.c
new file mode 100644
index 0000000000..0f21af2a91
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_ulonglong.c
@@ -0,0 +1,94 @@
+/*
+ * %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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+#include "ei_x_encode.h"
+
+/*
+ * For some 64 bit operations on some operating systems code
+ * compiled with GNU cc depends on "libgcc" for some 64 bit
+ * operations missing in hardware (or because of gcc bugs).
+ * If user code was linked together with the ei lib
+ * using other linkers than GNU ld this may cause problems.
+ * We moved ei_x_encode_ulonglong() here from "ei_x_encode.c"
+ * to limit this problem to users that actually use the ei
+ * longlong operations, not all ei_x users.
+ */
+int ei_x_encode_ulonglong(ei_x_buff* x, EI_ULONGLONG n)
+{
+ int i = x->index;
+ ei_encode_ulonglong(NULL, &i, n);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_ulonglong(x->buff, &x->index, n);
+}
+
+#ifdef EI_64BIT
+int ei_encode_ulong(char *buf, int *index, unsigned long p)
+{
+ return ei_encode_ulonglong(buf, index, p);
+}
+#endif
+
+int ei_encode_ulonglong(char *buf, int *index, EI_ULONGLONG p)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+
+ if ((p < 256) && (p >= 0)) {
+ if (!buf) s += 2;
+ else {
+ put8(s,ERL_SMALL_INTEGER_EXT);
+ put8(s,(p & 0xff));
+ }
+ } else if (p <= ERL_MAX) {
+ if (!buf) s += 5;
+ else {
+ put8(s,ERL_INTEGER_EXT);
+ put32be(s,p);
+ }
+ } else {
+ /* We know 28-64 bits needed, i.e four to eight bytes */
+ if (buf) {
+ char *arityp;
+ int arity = 0;
+ put8(s,ERL_SMALL_BIG_EXT);
+ arityp = s++; /* fill in later */
+ put8(s, 0); /* save sign separately */
+ while (p) {
+ *s++ = p & 0xff; /* take lowest byte */
+ p >>= 8; /* shift unsigned */
+ arity++;
+ }
+ put8(arityp,arity);
+ } else {
+ s += 3; /* Type, arity and sign */
+ while (p) {
+ s++; /* take lowest byte */
+ p >>= 8; /* shift unsigned */
+ }
+ }
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/encode/encode_version.c b/lib/erl_interface/src/encode/encode_version.c
new file mode 100644
index 0000000000..3fd9fdabd4
--- /dev/null
+++ b/lib/erl_interface/src/encode/encode_version.c
@@ -0,0 +1,35 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+/* add the version identifier to the start of the buffer */
+int ei_encode_version(char *buf, int *index)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+
+ if (!buf) s ++;
+ else put8(s,(unsigned char)ERL_VERSION_MAGIC);
+ *index += s-s0;
+
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/epmd/ei_epmd.h b/lib/erl_interface/src/epmd/ei_epmd.h
new file mode 100644
index 0000000000..40e5ece572
--- /dev/null
+++ b/lib/erl_interface/src/epmd/ei_epmd.h
@@ -0,0 +1,66 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef _EI_EPMD_H
+#define _EI_EPMD_H
+
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK ((u_long) 0x7F000001)
+#endif
+
+#ifndef EI_DIST_HIGH
+#define EI_DIST_HIGH 5 /* R4 and later */
+#define EI_DIST_LOW 1 /* R3 and earlier */
+#endif
+
+#ifndef EPMD_PORT
+#define EPMD_PORT 4369
+#endif
+
+#ifndef EPMDBUF
+#define EPMDBUF 512
+#endif
+
+#ifndef EI_MYPROTO
+#define EI_MYPROTO 0 /* tcp/ip */
+#endif
+
+/* epmd r3 protocol */
+#ifndef EI_EPMD_ALIVE_REQ
+#define EI_EPMD_ALIVE_REQ 'a'
+#define EI_EPMD_ALIVE_OK_RESP 'Y'
+#define EI_EPMD_PORT_REQ 'p'
+#define EI_EPMD_STOP_REQ 's'
+#endif
+
+/* epmd r4 */
+#ifndef EI_EPMD_ALIVE2_REQ
+#define EI_EPMD_ALIVE2_REQ 120
+#define EI_EPMD_ALIVE2_RESP 121
+#define EI_EPMD_PORT2_REQ 122
+#define EI_EPMD_PORT2_RESP 119
+#endif
+
+/* internal functions */
+int ei_epmd_connect_tmo(struct in_addr *inaddr, unsigned ms);
+int ei_epmd_publish(int port, const char *alive);
+int ei_epmd_publish_tmo(int port, const char *alive, unsigned ms);
+int ei_epmd_port(struct in_addr *inaddr, const char *alive, int *dist);
+int ei_epmd_port_tmo(struct in_addr *inaddr, const char *alive, int *dist, unsigned ms);
+
+#endif /* _EI_EPMD_H */
diff --git a/lib/erl_interface/src/epmd/epmd_port.c b/lib/erl_interface/src/epmd/epmd_port.c
new file mode 100644
index 0000000000..663b38d2d4
--- /dev/null
+++ b/lib/erl_interface/src/epmd/epmd_port.c
@@ -0,0 +1,299 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+
+#include "eidef.h"
+
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+
+#elif VXWORKS
+#include <vxWorks.h>
+#include <ifLib.h>
+#include <sockLib.h>
+#include <inetLib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ei.h"
+#include "ei_internal.h"
+#include "ei_epmd.h"
+#include "ei_portio.h"
+#include "putget.h"
+
+
+/* connect to epmd on given host (use NULL for localhost) */
+/*
+ * FIXME: Expects IPv4 addresses (excludes IPv6, Appletalk, IRDA and
+ * whatever) */
+int ei_epmd_connect_tmo(struct in_addr *inaddr, unsigned ms)
+{
+ static unsigned int epmd_port = 0;
+ struct sockaddr_in saddr;
+ int sd;
+ int res;
+
+ if (epmd_port == 0) {
+ char* port_str = getenv("ERL_EPMD_PORT");
+ epmd_port = (port_str != NULL) ? atoi(port_str) : EPMD_PORT;
+ }
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin_port = htons(epmd_port);
+ saddr.sin_family = AF_INET;
+
+ if (!inaddr) saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ else memmove(&saddr.sin_addr,inaddr,sizeof(saddr.sin_addr));
+
+ if (((sd = socket(PF_INET, SOCK_STREAM, 0)) < 0))
+ {
+ erl_errno = errno;
+ return -1;
+ }
+
+ if ((res = ei_connect_t(sd,(struct sockaddr *)&saddr,sizeof(saddr),ms)) < 0)
+ {
+ erl_errno = (res == -2) ? ETIMEDOUT : errno;
+ closesocket(sd);
+ return -1;
+ }
+
+ return sd;
+}
+
+/* get the given node's listen port using old epmd protocol */
+static int ei_epmd_r3_port (struct in_addr *addr, const char *alive,
+ unsigned ms)
+{
+ char buf[EPMDBUF];
+ char *s = buf;
+ int len = strlen(alive) + 1;
+ int fd;
+ int port;
+ int res;
+#if defined(VXWORKS)
+ char ntoabuf[32];
+#endif
+
+ put16be(s,len);
+ put8(s,EI_EPMD_PORT_REQ);
+ strcpy(s,alive);
+
+ /* connect to epmd */
+ if ((fd = ei_epmd_connect_tmo(addr,ms)) < 0)
+ {
+ /* ei_epmd_connect_tmo() sets erl_errno */
+ return -1;
+ }
+
+ if ((res = ei_write_fill_t(fd, buf, len+2, ms)) != len+2) {
+ closesocket(fd);
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+
+#ifdef VXWORKS
+ /* FIXME use union/macro for level. Correct level? */
+ if (ei_tracelevel > 2) {
+ inet_ntoa_b(*addr,ntoabuf);
+ EI_TRACE_CONN2("ei_epmd_r3_port",
+ "-> PORT_REQ alive=%s ip=%s",alive,ntoabuf);
+ }
+#else
+ EI_TRACE_CONN2("ei_epmd_r3_port",
+ "-> PORT_REQ alive=%s ip=%s",alive,inet_ntoa(*addr));
+#endif
+
+ if ((res = ei_read_fill_t(fd, buf, 2, ms)) != 2) {
+ EI_TRACE_ERR0("ei_epmd_r3_port","<- CLOSE");
+ closesocket(fd);
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+ closesocket(fd);
+ s = buf;
+ port = get16be(s);
+
+ EI_TRACE_CONN1("ei_epmd_r3_port","<- PORT_RESP port=%d",port);
+
+ return port;
+}
+
+static int ei_epmd_r4_port (struct in_addr *addr, const char *alive,
+ int *dist, unsigned ms)
+{
+ char buf[EPMDBUF];
+ char *s = buf;
+ int len = strlen(alive) + 1;
+ int fd;
+ int ntype;
+ int port;
+ int dist_high, dist_low, proto;
+ int res;
+#if defined(VXWORKS)
+ char ntoabuf[32];
+#endif
+
+ put16be(s,len);
+ put8(s,EI_EPMD_PORT2_REQ);
+ strcpy(s,alive);
+
+ /* connect to epmd */
+ if ((fd = ei_epmd_connect_tmo(addr,ms)) < 0)
+ {
+ return -1;
+ }
+
+ if ((res = ei_write_fill_t(fd, buf, len+2, ms)) != len+2) {
+ closesocket(fd);
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+
+#ifdef VXWORKS
+ /* FIXME use union/macro for level. Correct level? */
+ if (ei_tracelevel > 2) {
+ inet_ntoa_b(*addr,ntoabuf);
+ EI_TRACE_CONN2("ei_epmd_r4_port",
+ "-> PORT2_REQ alive=%s ip=%s",alive,ntoabuf);
+ }
+#else
+ EI_TRACE_CONN2("ei_epmd_r4_port",
+ "-> PORT2_REQ alive=%s ip=%s",alive,inet_ntoa(*addr));
+#endif
+
+ /* read first two bytes (response type, response) */
+ if ((res = ei_read_fill_t(fd, buf, 2, ms)) != 2) {
+ EI_TRACE_ERR0("ei_epmd_r4_port","<- CLOSE");
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ closesocket(fd);
+ return -2; /* version mismatch */
+ }
+
+ s = buf;
+ res = get8(s);
+
+ if (res != EI_EPMD_PORT2_RESP) { /* response type */
+ EI_TRACE_ERR1("ei_epmd_r4_port","<- unknown (%d)",res);
+ EI_TRACE_ERR0("ei_epmd_r4_port","-> CLOSE");
+ closesocket(fd);
+ erl_errno = EIO;
+ return -1;
+ }
+
+
+
+ /* got negative response */
+ if ((res = get8(s))) {
+ /* got negative response */
+ EI_TRACE_ERR1("ei_epmd_r4_port","<- PORT2_RESP result=%d (failure)",res);
+ closesocket(fd);
+ erl_errno = EIO;
+ return -1;
+ }
+
+ EI_TRACE_CONN1("ei_epmd_r4_port","<- PORT2_RESP result=%d (ok)",res);
+
+ /* expecting remaining 8 bytes */
+ if ((res = ei_read_fill_t(fd,buf,8,ms)) != 8) {
+ EI_TRACE_ERR0("ei_epmd_r4_port","<- CLOSE");
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ closesocket(fd);
+ return -1;
+ }
+
+ closesocket(fd);
+ s = buf;
+
+ port = get16be(s);
+ ntype = get8(s);
+ proto = get8(s);
+ dist_high = get16be(s);
+ dist_low = get16be(s);
+
+ EI_TRACE_CONN5("ei_epmd_r4_port",
+ " port=%d ntype=%d proto=%d dist-high=%d dist-low=%d",
+ port,ntype,proto,dist_high,dist_low);
+
+ /* right network protocol? */
+ if (EI_MYPROTO != proto)
+ {
+ erl_errno = EIO;
+ return -1;
+ }
+
+ /* is there overlap in our distribution versions? */
+ if ((EI_DIST_HIGH < dist_low) || (EI_DIST_LOW > dist_high))
+ {
+ erl_errno = EIO;
+ return -1;
+ }
+
+ /* choose the highest common version */
+ /* i.e. min(his-max, my-max) */
+ *dist = (dist_high > EI_DIST_HIGH ? EI_DIST_HIGH : dist_high);
+
+ /* ignore the remaining fields */
+ return port;
+}
+
+/* lookup the port number of the given node. 'dist' is an out-argument
+ * which, if the lookup is successful, will be initialized to contain
+ * the highest distribution version that is common to the calling node
+ * and the node looked up. The function will attempt to contact epmd
+ * version 4 before trying version 3. R3 (and earlier) nodes have
+ * dist=0.
+ */
+int ei_epmd_port (struct in_addr *addr, const char *alive, int *dist)
+{
+ return ei_epmd_port_tmo (addr, alive, dist, 0);
+}
+
+int ei_epmd_port_tmo (struct in_addr *addr, const char *alive, int *dist,
+ unsigned ms)
+{
+ int i;
+
+ /* try the new one first, then the old one */
+ i = ei_epmd_r4_port(addr,alive,dist,ms);
+
+ /* -2: new protocol not understood */
+ if (i == -2) {
+ *dist = 0;
+ i = ei_epmd_r3_port(addr,alive,ms);
+ }
+
+ return i;
+}
+
diff --git a/lib/erl_interface/src/epmd/epmd_publish.c b/lib/erl_interface/src/epmd/epmd_publish.c
new file mode 100644
index 0000000000..09b3dce43b
--- /dev/null
+++ b/lib/erl_interface/src/epmd/epmd_publish.c
@@ -0,0 +1,228 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+
+#include "eidef.h"
+
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+
+#elif VXWORKS
+#include <vxWorks.h>
+#include <ifLib.h>
+#include <sockLib.h>
+#include <inetLib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ei_internal.h"
+#include "putget.h"
+#include "ei_epmd.h"
+#include "ei_portio.h"
+
+
+/* publish our listen port and alive name */
+/* return the (useless) creation number */
+static int ei_epmd_r3_publish (int port, const char *alive, unsigned ms)
+{
+ char buf[EPMDBUF];
+ char *s = buf;
+ int fd;
+ int len = strlen(alive) + 3;
+ int res,creation;
+
+ s = buf;
+ put16be(s,len);
+ put8(s,EI_EPMD_ALIVE_REQ);
+ put16be(s,port);
+ strcpy(s, alive);
+
+ if ((fd = ei_epmd_connect_tmo(NULL,ms)) < 0) return fd;
+
+ if ((res = ei_write_fill_t(fd, buf, len+2, ms)) != len+2) {
+ closesocket(fd);
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+
+ EI_TRACE_CONN2("ei_epmd_r3_publish",
+ "-> ALIVE_REQ alive=%s port=%d",alive,port);
+
+ if ((res = ei_read_fill_t(fd, buf, 3, ms)) != 3) {
+ closesocket(fd);
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+
+ s = buf;
+ if ((res=get8(s)) != EI_EPMD_ALIVE_OK_RESP) {
+ EI_TRACE_ERR1("ei_epmd_r3_publish",
+ "<- ALIVE_NOK result=%d (failure)",res);
+ closesocket(fd);
+ erl_errno = EIO;
+ return -1;
+ }
+
+ creation = get16be(s);
+
+ EI_TRACE_CONN1("ei_epmd_r3_publish","<- ALIVE_OK creation=%d",creation);
+
+ /* Don't close fd here! It keeps us registered with epmd */
+
+ /* probably should save fd so we can close it later... */
+ /* epmd_saveconn(OPEN,fd,alive); */
+
+ /* return the creation number, for no good reason */
+ /* return creation; */
+
+ /* no! return the descriptor */
+ return fd;
+}
+
+/* publish our listen port and alive name */
+/* return the (useless) creation number */
+/* this protocol is a lot more complex than the old one */
+static int ei_epmd_r4_publish (int port, const char *alive, unsigned ms)
+{
+ char buf[EPMDBUF];
+ char *s = buf;
+ int fd;
+ int elen = 0;
+ int nlen = strlen(alive);
+ int len = elen + nlen + 13; /* hard coded: be careful! */
+ int n;
+ int res, creation;
+
+ s = buf;
+ put16be(s,len);
+
+ put8(s,EI_EPMD_ALIVE2_REQ);
+ put16be(s,port); /* port number */
+ put8(s,'h'); /* h = r4 hidden node */
+ put8(s, EI_MYPROTO); /* protocol 0 ?? */
+ put16be(s,EI_DIST_HIGH); /* highest understood version: 1 = R4 */
+ put16be(s,EI_DIST_LOW); /* lowest: 0 = R3 */
+ put16be(s,nlen); /* length of alivename */
+ strcpy(s, alive);
+ s += nlen;
+ put16be(s,elen); /* length of extra string = 0 */
+ /* no extra string */
+
+ if ((fd = ei_epmd_connect_tmo(NULL,ms)) < 0) return fd;
+
+ if ((res = ei_write_fill_t(fd, buf, len+2, ms)) != len+2) {
+ closesocket(fd);
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+
+ EI_TRACE_CONN6("ei_epmd_r4_publish",
+ "-> ALIVE2_REQ alive=%s port=%d ntype=%d "
+ "proto=%d dist-high=%d dist-low=%d",
+ alive,port,'H',EI_MYPROTO,EI_DIST_HIGH,EI_DIST_LOW);
+
+ if ((n = ei_read_fill_t(fd, buf, 4, ms)) != 4) {
+ EI_TRACE_ERR0("ei_epmd_r4_publish","<- CLOSE");
+ closesocket(fd);
+ erl_errno = (n == -2) ? ETIMEDOUT : EIO;
+ return -2; /* version mismatch */
+ }
+ /* Don't close fd here! It keeps us registered with epmd */
+ s = buf;
+ if (((res=get8(s)) != EI_EPMD_ALIVE2_RESP)) { /* response */
+ EI_TRACE_ERR1("ei_epmd_r4_publish","<- unknown (%d)",res);
+ EI_TRACE_ERR0("ei_epmd_r4_publish","-> CLOSE");
+ closesocket(fd);
+ erl_errno = EIO;
+ return -1;
+ }
+
+ EI_TRACE_CONN0("ei_epmd_r4_publish","<- ALIVE2_RESP");
+
+ if (((res=get8(s)) != 0)) { /* 0 == success */
+ EI_TRACE_ERR1("ei_epmd_r4_publish"," result=%d (fail)",res);
+ closesocket(fd);
+ erl_errno = EIO;
+ return -1;
+ }
+
+ creation = get16be(s);
+
+ EI_TRACE_CONN2("ei_epmd_r4_publish",
+ " result=%d (ok) creation=%d",res,creation);
+
+ /* probably should save fd so we can close it later... */
+ /* epmd_saveconn(OPEN,fd,alive); */
+
+ /* return the creation number, for no good reason */
+ /* return creation;*/
+
+ /* no - return the descriptor */
+ return fd;
+}
+
+int ei_epmd_publish(int port, const char *alive)
+{
+ return ei_epmd_publish_tmo(port, alive, 0);
+}
+
+int ei_epmd_publish_tmo(int port, const char *alive, unsigned ms)
+{
+ int i;
+
+ /* try the new one first, then the old one */
+ i = ei_epmd_r4_publish(port,alive, ms);
+
+ /* -2: new protocol not understood */
+ if (i == -2) i = ei_epmd_r3_publish(port,alive, ms);
+
+ return i;
+}
+
+
+/*
+ * Publish a name for our C-node.
+ * a file descriptor is returned - close it to unpublish.
+ *
+ */
+int ei_publish(ei_cnode* ec, int port)
+{
+ return ei_epmd_publish(port, ei_thisalivename(ec));
+}
+
+int ei_publish_tmo(ei_cnode* ec, int port, unsigned ms)
+{
+ return ei_epmd_publish_tmo(port, ei_thisalivename(ec), ms);
+}
diff --git a/lib/erl_interface/src/epmd/epmd_unpublish.c b/lib/erl_interface/src/epmd/epmd_unpublish.c
new file mode 100644
index 0000000000..08662fe1ec
--- /dev/null
+++ b/lib/erl_interface/src/epmd/epmd_unpublish.c
@@ -0,0 +1,106 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+
+#elif VXWORKS
+#include <vxWorks.h>
+#include <ifLib.h>
+#include <sockLib.h>
+#include <inetLib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "eidef.h"
+#include "ei_internal.h"
+#include "putget.h"
+#include "ei_epmd.h"
+#include "ei_portio.h"
+
+
+/* stop the specified node */
+int ei_unpublish_tmo(const char *alive, unsigned ms)
+{
+ char buf[EPMDBUF];
+ char *s = (char*)buf;
+ int len = 1 + strlen(alive);
+ int fd, res;
+
+ put16be(s,len);
+ put8(s,EI_EPMD_STOP_REQ);
+ strcpy(s, alive);
+
+ /* FIXME can't connect, return success?! At least commen whats up */
+ if ((fd = ei_epmd_connect_tmo(NULL,ms)) < 0) return fd;
+
+ if ((res = ei_write_fill_t(fd, buf, len+2,ms)) != len+2) {
+ closesocket(fd);
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+
+ EI_TRACE_CONN1("ei_unpublish_tmo","-> STOP %s",alive);
+
+ if ((res = ei_read_fill_t(fd, buf, 7, ms)) != 7) {
+ closesocket(fd);
+ erl_errno = (res == -2) ? ETIMEDOUT : EIO;
+ return -1;
+ }
+ closesocket(fd);
+ buf[7]=(char)0; /* terminate the string */
+
+ if (!strcmp("STOPPED",(char *)buf)) {
+ EI_TRACE_CONN0("ei_unpublish_tmo","<- STOPPED (success)");
+ return 0;
+ }
+ else if (!strcmp("NOEXIST",(char *)buf)) {
+ EI_TRACE_ERR0("ei_unpublish_tmo","<- NOEXIST (failure)");
+ erl_errno = EIO;
+ return -1;
+ }
+ else {
+ EI_TRACE_ERR0("ei_unpublish_tmo","<- unknown (failure)");
+ erl_errno = EIO;
+ return -1; /* this shouldn't happen */
+ }
+ return 0;
+}
+
+
+int ei_unpublish(ei_cnode* ec)
+{
+ return ei_unpublish_tmo(ei_thisalivename(ec),0);
+}
diff --git a/lib/erl_interface/src/legacy/decode_term.c b/lib/erl_interface/src/legacy/decode_term.c
new file mode 100644
index 0000000000..ef29d6f57d
--- /dev/null
+++ b/lib/erl_interface/src/legacy/decode_term.c
@@ -0,0 +1,142 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+#include "erl_interface.h"
+
+/*
+ * This file is actually part of the erl_interface library,
+ * not the newer 'ei' library. The header file is still in "ei.h"
+ */
+
+/* FIXME: is this to be completed? */
+
+#if (0)
+int ei_decode_term(const char *buf, int *index, void *t)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+
+ if (t) {
+ ETERM *tmp;
+
+ /* this decodes and advances s */
+ if (!(tmp = erl_decode_buf((unsigned char **)&s))) return -1;
+
+ *(ETERM **)t = tmp;
+ *index += s - s0;
+
+ return 0;
+ }
+ else {
+ int tmpindex = *index;
+ long ttype;
+ int arity;
+ int i;
+
+ /* these are all the external types */
+ switch ((ttype = get8(s))) {
+ case ERL_SMALL_INTEGER_EXT:
+ case ERL_INTEGER_EXT:
+ case ERL_SMALL_BIG_EXT:
+ return ei_decode_long(buf,index,NULL);
+
+ case ERL_FLOAT_EXT:
+ return ei_decode_double(buf,index,NULL);
+
+ case ERL_ATOM_EXT:
+ return ei_decode_atom(buf,index,NULL);
+
+ case ERL_REFERENCE_EXT:
+ case ERL_NEW_REFERENCE_EXT:
+ return ei_decode_ref(buf,index,NULL);
+
+ case ERL_PORT_EXT:
+ return ei_decode_port(buf,index,NULL);
+
+ case ERL_PID_EXT:
+ return ei_decode_pid(buf,index,NULL);
+
+ case ERL_SMALL_TUPLE_EXT:
+ case ERL_LARGE_TUPLE_EXT:
+ if (ei_decode_tuple_header(buf,index,&arity) < 0)
+ return -1;
+
+ for (i=0; i<arity; i++) {
+ if (ei_decode_term(buf,index,NULL)) {
+ /* restore possibly changed index before returning */
+ *index = tmpindex;
+ return -1;
+ }
+ }
+ return 0;
+
+ case ERL_STRING_EXT:
+ return ei_decode_string(buf,index,NULL);
+
+ case ERL_LIST_EXT:
+ case ERL_NIL_EXT:
+ if (ei_decode_list_header(buf,index,&arity) < 0)
+ return -1;
+
+ if (arity) {
+ for (i=0; i<arity; i++) {
+ if (ei_decode_term(buf,index,NULL) < 0) {
+ /* restore possibly changed index before returning */
+ *index = tmpindex;
+ return -1;
+ }
+ }
+ if (ei_decode_list_header(buf,index,&arity) < 0) {
+ *index = tmpindex;
+ return -1;
+ }
+ }
+ return 0;
+
+ case ERL_BINARY_EXT:
+ return ei_decode_binary(buf,index,NULL,NULL);
+
+ case ERL_LARGE_BIG_EXT:
+ default:
+ break;
+ }
+ }
+
+ return -1;
+}
+#else
+int ei_decode_term(const char *buf, int *index, void *t)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ ETERM *tmp;
+
+ /* this decodes and advances s */
+ if (!(tmp = erl_decode_buf((unsigned char **)&s))) return -1;
+
+ if (t) *(ETERM **)t = tmp;
+ else erl_free_term(tmp);
+
+ *index += s - s0;
+
+ return 0;
+}
+#endif
diff --git a/lib/erl_interface/src/legacy/encode_term.c b/lib/erl_interface/src/legacy/encode_term.c
new file mode 100644
index 0000000000..c377d7b699
--- /dev/null
+++ b/lib/erl_interface/src/legacy/encode_term.c
@@ -0,0 +1,53 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+#include "ei_x_encode.h"
+#include "erl_interface.h"
+#include "erl_marshal.h"
+
+/* FIXME: depends on old erl_interface */
+
+int ei_x_encode_term(ei_x_buff* x, void* t)
+{
+ int i = x->index;
+ ei_encode_term(NULL, &i, t);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_term(x->buff, &x->index, t);
+}
+
+int ei_encode_term(char *buf, int *index, void *t)
+{
+ char *s = buf + *index;
+ char *s0 = s;
+
+ if (!buf) s += erl_term_len(t) -1; /* -1 for version */
+ else {
+ /* this encodes all but the version at the start */
+ /* and it will move s forward the right number of bytes */
+ if (erl_encode_it(t,(unsigned char **)&s, 5)) return -1;
+ }
+
+ *index += s - s0;
+
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/legacy/erl_config.h b/lib/erl_interface/src/legacy/erl_config.h
new file mode 100644
index 0000000000..166aa7013c
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_config.h
@@ -0,0 +1,22 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef _ERL_CONFIG_H
+#define _ERL_CONFIG_H
+
+#endif /* _ERL_CONFIG_H */
diff --git a/lib/erl_interface/src/legacy/erl_connect.c b/lib/erl_interface/src/legacy/erl_connect.c
new file mode 100644
index 0000000000..3c8c946506
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_connect.c
@@ -0,0 +1,457 @@
+/*
+ * %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%
+ */
+/*
+ * Purpose: Connect to any node at any host.
+ */
+
+/***************************************************************************
+ *
+ * 'erl_interface' node connection handling is to use 'ei' for all
+ * operations without access to the internal structure of saved data,
+ * e.i. it should use the public interface functions. The connection
+ * handling can be seen as a restricted node interface where only one
+ * node can be used in one operating system process.
+ *
+ ***************************************************************************/
+
+#include "eidef.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+
+#elif VXWORKS
+#include <vxWorks.h>
+#include <hostLib.h>
+#include <selectLib.h>
+#include <ifLib.h>
+#include <sockLib.h>
+#include <taskLib.h>
+#include <inetLib.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/times.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <timers.h>
+
+#include "erl_error.h"
+
+#else /* some other unix */
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/times.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/utsname.h> /* for gen_challenge (NEED FIX?) */
+#endif
+
+/* common includes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/* FIXME include less */
+#include "erl_interface.h"
+#include "erl_connect.h"
+#include "erl_eterm.h"
+#include "erl_malloc.h"
+#include "putget.h"
+#include "ei.h"
+#include "ei_connect_int.h"
+#include "ei_locking.h"
+#include "ei_epmd.h"
+#include "ei_internal.h"
+
+/* rpc_from() uses a buffer this size */
+#ifndef MAX_RECEIVE_BUF
+#define MAX_RECEIVE_BUF 32*1024
+#endif
+
+/* This is the global state of the old erl_* API */
+
+static ei_cnode erl_if_ec;
+
+/***************************************************************************
+ *
+ * API: erl_connect_init()
+ * API: erl_connect_xinit()
+ *
+ * Returns 1 on success and 0 on failure.
+ * Not documented to set erl_errno.
+ *
+ ***************************************************************************/
+
+int erl_connect_init(int this_node_number, char *cookie, short creation)
+{
+ char nn[MAXATOMLEN+1];
+
+ sprintf(nn, "c%d", this_node_number);
+
+ return ei_connect_init(&erl_if_ec, nn, cookie, creation) == 0;
+}
+
+/* FIXME documented to use struct in_addr as addr */
+
+int erl_connect_xinit(char *thishostname,
+ char *thisalivename,
+ char *thisnodename,
+ struct in_addr *thisipaddr,
+ char *cookie,
+ short creation)
+{
+ return ei_connect_xinit(&erl_if_ec, thishostname, thisalivename,
+ thisnodename, thisipaddr, cookie, creation) >= 0;
+}
+
+/***************************************************************************
+ *
+ * API: erl_connect()
+ * API: erl_xconnect()
+ *
+ * Set up a connection to a given Node, and interchange hand shake
+ * messages with it.
+ *
+ * Returns valid file descriptor on success and < 0 on failure.
+ * Set erl_errno to EHOSTUNREACH, ENOMEM, EIO or errno from socket(2)
+ * or connect(2).
+ *
+ ***************************************************************************/
+
+int erl_connect(char *nodename)
+{
+ int res = ei_connect(&erl_if_ec, nodename);
+ if (res < 0) erl_errno = EIO;
+ return res;
+}
+
+/* FIXME documented to use struct in_addr as addr */
+
+int erl_xconnect(Erl_IpAddr addr, char *alivename)
+{
+ return ei_xconnect(&erl_if_ec, addr, alivename);
+}
+
+
+/***************************************************************************
+ *
+ * API: erl_close_connection()
+ *
+ * Close a connection. FIXME call ei_close_connection() later.
+ *
+ * Returns valid file descriptor on success and < 0 on failure.
+ * Set erl_errno to EHOSTUNREACH, ENOMEM, EIO or errno from socket(2)
+ * or connect(2).
+ *
+ ***************************************************************************/
+
+int erl_close_connection(int fd)
+{
+ return closesocket(fd);
+}
+
+/*
+ * Accept and initiate a connection from an other
+ * Erlang node. Return a file descriptor at success,
+ * otherwise -1;
+ */
+int erl_accept(int lfd, ErlConnect *conp)
+{
+ return ei_accept(&erl_if_ec, lfd, conp);
+}
+
+
+/* Receives a message from an Erlang socket.
+ * If the message was a TICK it is immediately
+ * answered. Returns: ERL_ERROR, ERL_TICK or
+ * the number of bytes read.
+ */
+int erl_receive(int s, unsigned char *bufp, int bufsize)
+{
+ return ei_receive(s, bufp, bufsize);
+}
+
+/*
+ * Send an Erlang message to a registered process
+ * at the Erlang node, connected with a socket.
+ */
+int erl_reg_send(int fd, char *server_name, ETERM *msg)
+{
+ ei_x_buff x;
+ int r;
+
+ ei_x_new_with_version(&x);
+ if (ei_x_encode_term(&x, msg) < 0) {
+ erl_errno = EINVAL;
+ r = 0;
+ } else {
+ r = ei_reg_send(&erl_if_ec, fd, server_name, x.buff, x.index);
+ }
+ ei_x_free(&x);
+ return r == 0;
+}
+
+/*
+ * Sends an Erlang message to a process at an Erlang node
+ */
+int erl_send(int fd, ETERM *to ,ETERM *msg)
+{
+ erlang_pid topid;
+ ei_x_buff x;
+ int r;
+
+ ei_x_new_with_version(&x);
+ ei_x_encode_term(&x, msg);
+ /* make the to-pid */
+ if (!ERL_IS_PID(to)) {
+ ei_x_free(&x);
+ erl_errno = EINVAL;
+ return -1;
+ }
+
+ strcpy(topid.node, (char *)ERL_PID_NODE(to));
+ topid.num = ERL_PID_NUMBER(to);
+ topid.serial = ERL_PID_SERIAL(to);
+ topid.creation = ERL_PID_CREATION(to);
+ r = ei_send(fd, &topid, x.buff, x.index);
+ ei_x_free(&x);
+ return r == 0;
+}
+
+static int erl_do_receive_msg(int fd, ei_x_buff* x, ErlMessage* emsg)
+{
+ erlang_msg msg;
+
+ int r;
+ msg.from.node[0] = msg.to.node[0] = '\0';
+ r = ei_do_receive_msg(fd, 0, &msg, x, 0);
+
+ if (r == ERL_MSG) {
+ int index = 0;
+ emsg->type = msg.msgtype;
+
+ /*
+ We can't call ei_decode_term for cases where there are no
+ data following the type information. If there are other
+ types added later where there are data this case has to be
+ extended.
+ */
+
+ switch (msg.msgtype) {
+ case ERL_SEND:
+ case ERL_REG_SEND:
+ case ERL_EXIT:
+ case ERL_EXIT2:
+ if (ei_decode_term(x->buff, &index, &emsg->msg) < 0)
+ r = ERL_ERROR;
+ break;
+ default:
+ emsg->msg = NULL; /* Not needed but may avoid problems for unsafe caller */
+ break;
+ }
+ } else
+ emsg->msg = NULL;
+ if (msg.from.node[0] != '\0')
+ emsg->from = erl_mk_pid(msg.from.node, msg.from.num, msg.from.serial, msg.from.creation);
+ if (msg.to.node[0] != '\0')
+ emsg->to = erl_mk_pid(msg.to.node, msg.to.num, msg.to.serial, msg.to.creation);
+ return r;
+}
+
+int erl_receive_msg(int fd, unsigned char *buf, int bufsize, ErlMessage *emsg)
+{
+ ei_x_buff x;
+ int r;
+
+ ei_x_new(&x);
+ r = erl_do_receive_msg(fd, &x, emsg);
+ /* FIXME what is this about? */
+ if (bufsize > x.index)
+ bufsize = x.index;
+ memcpy(buf, x.buff, bufsize);
+ ei_x_free(&x);
+ return r;
+}
+
+int erl_xreceive_msg(int fd, unsigned char **buf, int *bufsize,
+ ErlMessage *emsg)
+{
+ ei_x_buff x;
+ int r;
+
+ ei_x_new(&x);
+ r = erl_do_receive_msg(fd, &x, emsg);
+ if (*bufsize < x.index)
+ *buf = erl_realloc(*buf, x.index);
+ *bufsize = x.index;
+ memcpy(*buf, x.buff, *bufsize);
+ ei_x_free(&x);
+ return r;
+}
+
+/*
+ * The RPC consists of two parts, send and receive.
+ * Here is the send part !
+ * { PidFrom, { call, Mod, Fun, Args, user }}
+ */
+/*
+ * Now returns non-negative number for success, negative for failure.
+ */
+int erl_rpc_to(int fd, char *mod, char *fun, ETERM *args)
+{
+ int r;
+ ei_x_buff x;
+
+ ei_x_new(&x);
+ ei_x_encode_term(&x, args);
+ r = ei_rpc_to(&erl_if_ec, fd, mod, fun, x.buff, x.index);
+ ei_x_free(&x);
+ return r;
+} /* rpc_to */
+
+ /*
+ * And here is the rpc receiving part. A negative
+ * timeout means 'infinity'. Returns either of: ERL_MSG,
+ * ERL_TICK, ERL_ERROR or ERL_TIMEOUT.
+*/
+int erl_rpc_from(int fd, int timeout, ErlMessage *emsg)
+{
+ fd_set readmask;
+ struct timeval tv;
+ struct timeval *t = NULL;
+ unsigned char rbuf[MAX_RECEIVE_BUF];
+
+ if (timeout >= 0) {
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ t = &tv;
+ }
+
+ FD_ZERO(&readmask);
+ FD_SET(fd,&readmask);
+
+ switch (select(fd+1, &readmask, NULL, NULL, t)) {
+ case -1:
+ erl_errno = EIO;
+ return ERL_ERROR;
+ case 0:
+ erl_errno = ETIMEDOUT;
+ return ERL_TIMEOUT;
+ default:
+ if (FD_ISSET(fd, &readmask))
+ return erl_receive_msg(fd, rbuf, MAX_RECEIVE_BUF, emsg);
+ else {
+ erl_errno = EIO;
+ return ERL_ERROR;
+ }
+ }
+} /* rpc_from */
+
+/*
+ * A true RPC. It return a NULL pointer
+ * in case of failure, otherwise a valid
+ * (ETERM *) pointer containing the reply
+ */
+ETERM *erl_rpc(int fd, char *mod, char *fun, ETERM *args)
+{
+ int i;
+ ETERM *ep;
+ ErlMessage emsg;
+
+ if (erl_rpc_to(fd, mod, fun, args) < 0) {
+ return NULL; }
+ while ((i=erl_rpc_from(fd, ERL_NO_TIMEOUT, &emsg)) == ERL_TICK);
+
+ if (i == ERL_ERROR) return NULL;
+
+ ep = erl_element(2,emsg.msg); /* {RPC_Tag, RPC_Reply} */
+ erl_free_term(emsg.msg);
+ erl_free_term(emsg.to);
+ return ep;
+} /* rpc */
+
+
+/*
+ ** Handshake
+ */
+
+int erl_publish(int port)
+{
+ return ei_publish(&erl_if_ec, port);
+}
+
+int erl_unpublish(const char *alive)
+{
+ return ei_unpublish_tmo(alive,0);
+}
+
+erlang_pid *erl_self(void)
+{
+ return ei_self(&erl_if_ec);
+}
+
+const char *erl_thisnodename(void)
+{
+ return ei_thisnodename(&erl_if_ec);
+}
+
+const char *erl_thishostname(void)
+{
+ return ei_thishostname(&erl_if_ec);
+}
+
+const char *erl_thisalivename(void)
+{
+ return ei_thisalivename(&erl_if_ec);
+}
+
+const char *erl_thiscookie(void)
+{
+ return ei_thiscookie(&erl_if_ec);
+}
+
+short erl_thiscreation(void)
+{
+ return ei_thiscreation(&erl_if_ec);
+}
diff --git a/lib/erl_interface/src/legacy/erl_connect.h b/lib/erl_interface/src/legacy/erl_connect.h
new file mode 100644
index 0000000000..d9d6c4e453
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_connect.h
@@ -0,0 +1,24 @@
+/*
+ * %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%
+ */
+#ifndef _ERL_CONNECT_H
+#define _ERL_CONNECT_H
+
+erlang_pid *erl_self(void);
+
+#endif /* _ERL_CONNECT_H */
diff --git a/lib/erl_interface/src/legacy/erl_error.c b/lib/erl_interface/src/legacy/erl_error.c
new file mode 100644
index 0000000000..18dc2423bf
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_error.c
@@ -0,0 +1,180 @@
+/*
+ * %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%
+ */
+/*
+ * Function: Some nice error routines taken from:
+ * "Advanced Programming in the UNIX Environment",
+ * by W.Richard Stevens
+ *
+ * void erl_err_sys(const char *fmt, ... ) fatal, sys-error
+ * void erl_err_ret(const char *fmt, ... ) non-fatal, sys-error
+ * void erl_err_quit(const char *fmt, ...) fatal, non-sys-error
+ * void erl_err_msg(const char *fmt, ... ) non-fatal, non-sys-error
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef VRTX /* What's VRIX? [sverkerw] */
+#define __READY_EXTENSIONS__
+#endif
+#include <errno.h>
+
+#if defined(VXWORKS)
+#include <taskLib.h>
+#include <taskVarLib.h>
+#endif
+
+#include "eidef.h"
+#include "erl_interface.h"
+#include "erl_error.h"
+
+/* Forward */
+static void err_doit(int, const char*, va_list);
+/* __attribute__ ((format (printf, 2, 0)))*/
+
+/*
+ * Some thoughts on flushing stdout/stderr:
+ *
+ * The defaults are reasonable (linebuffered stdout, unbuffered
+ * stderr). If they are in effect (the user neither knows nor cares),
+ * there's no need to flush.
+ *
+ * If the user changes these defaults (and knows what he's doing, so
+ * he knows and cares) we shouldn't surprise him by
+ * second-guessing. So there's a need to not flush.
+ *
+ * If the user doesn't know what he's doing, he's hosed anyway.
+ */
+
+/* Fatal error related to a system call.
+ * Print a message and terminate.
+ */
+void erl_err_sys(const char *fmt, ... )
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ err_doit(1, fmt, ap);
+ va_end(ap);
+ exit(1);
+} /* erl_err_sys */
+
+/* Nonfatal error related to a system call.
+ * Print a message and return
+ */
+void erl_err_ret(const char *fmt, ... )
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ err_doit(1, fmt, ap);
+ va_end(ap);
+ return;
+} /* erl_err_ret */
+
+/* Nonfatal error unrelated to a system call.
+ * Print a message and return
+ */
+void erl_err_msg(const char *fmt, ... )
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ err_doit(0, fmt, ap);
+ va_end(ap);
+ return;
+} /* erl_err_msg */
+
+/* Fatal error unrelated to a system call.
+ * Print a message and terminate
+ */
+void erl_err_quit(const char *fmt, ... )
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ err_doit(0, fmt, ap);
+ va_end(ap);
+ exit(1);
+} /* erl_err_quit */
+
+
+
+/*
+ * For example on SunOS we don't have the ANSI C strerror.
+ *
+ * maybe move to a convenince lib [sverkerw]
+ */
+#ifndef HAVE_STRERROR
+
+/* FIXME: move to configure */
+/* CONFIG: probe for sys_nerr/_sys_nerr */
+extern int sys_nerr;
+
+/* CONFIG: probe for sys_errlist/_sys_errlist and maybe for const-ness */
+#ifdef FREEBSD
+extern const char * const sys_errlist[];
+#else
+extern char * sys_errlist[];
+#endif
+
+/* Should be in string.h */
+/* Is supposed to return 'char *' (no const-ness in ANSI's prototype),
+ but if you rewrite the returned string in place you deserve to
+ lose. */
+static const char *strerror(int errnum)
+{
+ if (errnum >= 0 && errnum < sys_nerr) {
+ return sys_errlist[errnum];
+ } else {
+ /* Enough buffer for 64 bits of error. It should last a while. */
+ /* FIXME problem for threaded ? */
+ static char b[] = "(error -9223372036854775808)";
+ sprintf(b, "(error %d)", errnum);
+ buf[sizeof(b)-1] = '\0';
+ return b;
+ }
+}
+#endif /* !HAVE_STRERROR */
+
+
+/* Print a message and return to caller.
+ * Caller specifies "errnoflag".
+ */
+static void err_doit(int errnoflag, const char *fmt, va_list ap)
+{
+#ifndef NO_ERR_MSG
+ int errno_save;
+
+ errno_save = errno;
+
+ vfprintf(stderr, fmt, ap);
+ if (errnoflag)
+ {
+ fputs(": ", stderr);
+ fputs(strerror(errno_save), stderr);
+ }
+ fputs("\n", stderr);
+#endif
+
+ return;
+} /* err_doit */
+
diff --git a/lib/erl_interface/src/legacy/erl_error.h b/lib/erl_interface/src/legacy/erl_error.h
new file mode 100644
index 0000000000..931c639c30
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_error.h
@@ -0,0 +1,25 @@
+/*
+ * %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%
+ */
+#ifndef _ERL_ERROR_H
+#define _ERL_ERROR_H
+
+/* Initialize thread/task-safe erl_errno handling */
+void erl_init_errno(void);
+
+#endif /* _ERL_ERROR_H */
diff --git a/lib/erl_interface/src/legacy/erl_eterm.c b/lib/erl_interface/src/legacy/erl_eterm.c
new file mode 100644
index 0000000000..b685709c02
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_eterm.c
@@ -0,0 +1,1308 @@
+/*
+ * %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%
+ */
+/*
+ * Purpose: Representation of Erlang terms.
+ */
+
+#include "eidef.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "ei_locking.h"
+#include "ei_resolve.h"
+#include "erl_interface.h"
+#include "erl_eterm.h"
+#include "erl_malloc.h"
+#include "erl_marshal.h"
+#include "erl_error.h"
+#include "erl_internal.h"
+#include "ei_internal.h"
+
+#define ERL_IS_BYTE(x) (ERL_IS_INTEGER(x) && (ERL_INT_VALUE(x) & ~0xFF) == 0)
+
+/* FIXME use unsigned char, or uint8 for buffers, cast (int) really needed? */
+
+static void iolist_to_buf(const ETERM* term, char** bufp);
+static char* strsave(const char *src);
+
+/***************************************************************************
+ *
+ * API: erl_init()
+ *
+ * Not documented to set erl_errno.
+ *
+ ***************************************************************************/
+
+/* all initialisation of erl_interface modules should be called from here */
+/* order is important: erl_malloc and erl_resolve depend on ei_locking */
+/* NOTE: don't call this directly - please use erl_init() macro defined
+ in ei_locking.h! */
+void erl_init(void *hp,long heap_size)
+{
+ erl_init_malloc(hp, heap_size);
+ erl_init_marshal();
+ ei_init_resolve();
+}
+
+void erl_set_compat_rel(unsigned rel)
+{
+ ei_set_compat_rel(rel);
+}
+
+/*
+ * Create an INTEGER. Depending on its value it
+ * may end up as a BigNum.
+ */
+ETERM *erl_mk_int (int i)
+{
+ ETERM *ep;
+
+ ep = erl_alloc_eterm(ERL_INTEGER);
+ ERL_COUNT(ep) = 1;
+ ERL_INT_VALUE(ep) = i;
+ return ep;
+}
+
+ETERM *erl_mk_longlong (long long i)
+{
+ ETERM *ep;
+
+ ep = erl_alloc_eterm(ERL_LONGLONG);
+ ERL_COUNT(ep) = 1;
+ ERL_LL_VALUE(ep) = i;
+ return ep;
+}
+
+/*
+ * Create an UNSIGNED INTEGER. Depending on its
+ * value it may end up as a BigNum.
+ */
+
+ETERM *erl_mk_uint (unsigned int u)
+{
+ ETERM *ep;
+
+ ep = erl_alloc_eterm(ERL_U_INTEGER);
+ ERL_COUNT(ep) = 1;
+ ERL_INT_UVALUE(ep) = u;
+ return ep;
+}
+
+ETERM *erl_mk_ulonglong (unsigned long long i)
+{
+ ETERM *ep;
+
+ ep = erl_alloc_eterm(ERL_U_LONGLONG);
+ ERL_COUNT(ep) = 1;
+ ERL_LL_UVALUE(ep) = i;
+ return ep;
+}
+
+/*
+ * Create a FLOAT.
+ */
+ETERM *erl_mk_float (double d)
+{
+ ETERM *ep;
+
+ ep = erl_alloc_eterm(ERL_FLOAT);
+ ERL_COUNT(ep) = 1;
+ ERL_FLOAT_VALUE(ep) = d;
+ return ep;
+}
+
+/*
+ * Create an ATOM
+ */
+ETERM *erl_mk_atom (const char *s)
+{
+ ETERM *ep;
+
+ /* ASSERT(s != NULL); */
+ if (!s) return NULL;
+
+ ep = erl_alloc_eterm(ERL_ATOM);
+ ERL_COUNT(ep) = 1;
+ ERL_ATOM_SIZE(ep) = strlen(s);
+ if ((ERL_ATOM_PTR(ep) = strsave(s)) == NULL)
+ {
+ erl_free_term(ep);
+ erl_errno = ENOMEM;
+ return NULL;
+ }
+ return ep;
+}
+
+/*
+ * Given a string as input, creates a list.
+ */
+ETERM *erl_mk_string(const char *s)
+{
+ /* ASSERT(s != NULL); */
+ if (!s) return NULL;
+
+ return erl_mk_estring(s, strlen(s));
+}
+
+ETERM *erl_mk_estring(const char *s, int len)
+{
+ ETERM *ep;
+ int i;
+
+ if ((!s) || (len < 0)) return NULL;
+
+ /*
+ * ASSERT(s != NULL);
+ * ASSERT(len >= 0);
+ */
+
+ ep = erl_mk_empty_list();
+ for (i = len-1; i >= 0; i--) {
+ ETERM* integer;
+ ETERM* cons;
+
+ integer = erl_alloc_eterm(ERL_INTEGER);
+ ERL_COUNT(integer) = 1;
+ ERL_INT_VALUE(integer) = (unsigned char)s[i];
+
+ cons = erl_alloc_eterm(ERL_LIST);
+ ERL_COUNT(cons) = 1;
+ HEAD(cons) = integer;
+ TAIL(cons) = ep;
+ ep = cons;
+ }
+ return ep;
+}
+
+/*
+ * Create a PID.
+ */
+ETERM *erl_mk_pid(const char *node,
+ unsigned int number,
+ unsigned int serial,
+ unsigned char creation)
+{
+ ETERM *ep;
+
+ if (!node) return NULL;
+ /* ASSERT(node != NULL); */
+
+ ep = erl_alloc_eterm(ERL_PID);
+ ERL_COUNT(ep) = 1;
+ if ((ERL_PID_NODE(ep) = strsave(node)) == NULL)
+ {
+ erl_free_term(ep);
+ erl_errno = ENOMEM;
+ return NULL;
+ }
+ ERL_PID_NUMBER(ep) = number & 0x7fff; /* 15 bits */
+ if (ei_internal_use_r9_pids_ports()) {
+ ERL_PID_SERIAL(ep) = serial & 0x07; /* 3 bits */
+ }
+ else {
+ ERL_PID_SERIAL(ep) = serial & 0x1fff; /* 13 bits */
+ }
+ ERL_PID_CREATION(ep) = creation & 0x03; /* 2 bits */
+ return ep;
+}
+
+/*
+ * Create a PORT.
+ */
+ETERM *erl_mk_port(const char *node,
+ unsigned int number,
+ unsigned char creation)
+{
+ ETERM *ep;
+
+ if (!node) return NULL;
+ /* ASSERT(node != NULL); */
+
+ ep = erl_alloc_eterm(ERL_PORT);
+ ERL_COUNT(ep) = 1;
+ if ((ERL_PORT_NODE(ep) = strsave(node)) == NULL)
+ {
+ erl_free_term(ep);
+ erl_errno = ENOMEM;
+ return NULL;
+ }
+ if (ei_internal_use_r9_pids_ports()) {
+ ERL_PORT_NUMBER(ep) = number & 0x3ffff; /* 18 bits */
+ }
+ else {
+ ERL_PORT_NUMBER(ep) = number & 0x0fffffff; /* 18 bits */
+ }
+ ERL_PORT_CREATION(ep) = creation & 0x03; /* 2 bits */
+ return ep;
+}
+
+/*
+ * Create any kind of reference.
+ */
+ETERM *__erl_mk_reference (const char *node,
+ size_t len,
+ unsigned int n[],
+ unsigned char creation)
+{
+ ETERM * t;
+
+ if (node == NULL) return NULL;
+
+ t = erl_alloc_eterm(ERL_REF);
+ ERL_COUNT(t) = 1;
+
+ if ((ERL_REF_NODE(t) = strsave(node)) == NULL)
+ {
+ erl_free_term(t);
+ erl_errno = ENOMEM;
+ return NULL;
+ }
+ ERL_REF_LEN(t) = len;
+ ERL_REF_NUMBERS(t)[0] = n[0] & 0x3ffff; /* 18 bits */
+ ERL_REF_NUMBERS(t)[1] = n[1];
+ ERL_REF_NUMBERS(t)[2] = n[2];
+ ERL_REF_CREATION(t) = creation & 0x03; /* 2 bits */
+
+ return t;
+}
+
+/*
+ * Create a REFERENCE.
+ */
+ETERM *erl_mk_ref (const char *node,
+ unsigned int number,
+ unsigned char creation)
+{
+ unsigned int n[3] = {0, 0, 0};
+ n[0] = number;
+ return __erl_mk_reference(node, 1, n, creation);
+}
+
+/*
+ * Create a long REFERENCE.
+ */
+ETERM *
+erl_mk_long_ref (const char *node,
+ unsigned int n1, unsigned int n2, unsigned int n3,
+ unsigned char creation)
+{
+ unsigned int n[3] = {0, 0, 0};
+ n[0] = n3; n[1] = n2; n[2] = n1;
+ return __erl_mk_reference(node, 3, n, creation);
+}
+
+/*
+ * Create a BINARY.
+ */
+ETERM *erl_mk_binary (const char *b, int size)
+{
+ ETERM *ep;
+
+ if ((!b) || (size < 0)) return NULL;
+ /* ASSERT(b != NULL); */
+
+ ep = erl_alloc_eterm(ERL_BINARY);
+ ERL_COUNT(ep) = 1;
+ ERL_BIN_SIZE(ep) = size;
+ ERL_BIN_PTR(ep) = (unsigned char *) erl_malloc(size);
+ memcpy(ERL_BIN_PTR(ep), b, size);
+ return ep;
+}
+
+/*
+ * Create a TUPLE. For each element in the tuple
+ * bump its reference counter.
+ */
+ETERM *erl_mk_tuple (ETERM **arr,int size)
+{
+ ETERM *ep;
+ int i;
+
+ if ((!arr) || (size < 0)) return NULL;
+ for (i=0; i<size; i++) if (!arr[i]) return NULL;
+ /* ASSERT(arr != NULL); */
+
+ ep = erl_alloc_eterm(ERL_TUPLE);
+ ERL_COUNT(ep) = 1;
+ ERL_TUPLE_SIZE(ep) = size;
+ ERL_TUPLE_ELEMS(ep) = (ETERM**) erl_malloc((size) * (sizeof(ETERM*)));
+ for (i = 0; i < size; i++) {
+ /* ASSERT(arr[i] != NULL); */
+ ERL_COUNT(arr[i])++;
+ ERL_TUPLE_ELEMENT(ep, i) = arr[i];
+ }
+ return ep;
+}
+
+/*
+ * SET an ELEMENT in a TUPLE. Free the old element
+ * and bump the reference counter of the new one.
+ * Return 1 on success, otherwise 0.
+ */
+#if 0
+int erl_setelement (int ix, ETERM *ep, ETERM *vp)
+{
+ if ((!ep) || (!vp)) return 0;
+ /* ASSERT(ep != NULL);
+ * ASSERT(vp != NULL);
+ */
+
+ if ((ERL_TYPE(ep) == ERL_TUPLE) && (ix <= ERL_TUPLE_SIZE(ep))) {
+ erl_free_term(ERL_TUPLE_ELEMENT(ep, ix-1));
+ ERL_TUPLE_ELEMENT(ep, ix-1) = vp;
+ ERL_COUNT(vp)++;
+ return 1;
+ }
+ erl_err_msg("<ERROR> erl_setelement: Bad type to setelement or out of range \n");
+ return 0;
+}
+#endif
+
+/*
+ * Extract an ELEMENT from a TUPLE. Bump the
+ * reference counter on the extracted object.
+ */
+ETERM *erl_element (int ix, const ETERM *ep)
+{
+ if ((!ep) || (ix < 0)) return NULL;
+ /*
+ * ASSERT(ep != NULL);
+ * ASSERT(ix >= 0);
+ */
+
+ if ((ERL_TYPE(ep) == ERL_TUPLE) && (ix <= ERL_TUPLE_SIZE(ep))) {
+ ERL_COUNT(ERL_TUPLE_ELEMENT(ep, ix-1))++;
+ return ERL_TUPLE_ELEMENT(ep, ix-1);
+ }
+ else
+ return NULL;
+} /* erl_element */
+
+ETERM *erl_mk_empty_list(void)
+{
+ ETERM *ep;
+
+ ep = erl_alloc_eterm(ERL_EMPTY_LIST);
+ ERL_COUNT(ep) = 1;
+ return ep;
+}
+
+/*
+ * Construct a new list by CONS'ing a HEAD on
+ * to the TAIL. Bump the reference counter on
+ * the head and tail object. Note that we allow
+ * non-well formed lists to be created.
+ */
+ETERM *erl_cons(ETERM *hd, ETERM *tl)
+{
+ ETERM *ep;
+
+ if ((!hd) || (!tl)) return NULL;
+
+ /*
+ * ASSERT(hd != NULL);
+ * ASSERT(tl != NULL);
+ */
+
+ ep = erl_alloc_eterm(ERL_LIST);
+ ERL_COUNT(ep) = 1;
+ HEAD(ep) = hd;
+ TAIL(ep) = tl;
+ ERL_COUNT(hd)++;
+ ERL_COUNT(tl)++;
+ return ep;
+}
+
+/*
+ * Extract the HEAD of a LIST. Bump the reference
+ * counter on the head object.
+ */
+ETERM *erl_hd (const ETERM *ep)
+{
+ if (!ep) return NULL;
+ /* ASSERT(ep != NULL); */
+
+ if (ERL_TYPE(ep) != ERL_LIST) {
+ return (ETERM *) NULL;
+ }
+ ERL_COUNT(ERL_CONS_HEAD(ep))++;
+ return ERL_CONS_HEAD(ep);
+}
+
+/*
+ * Extract the TAIL of a LIST. Bump the reference
+ * counter on the tail object.
+ */
+ETERM *erl_tl (const ETERM *ep)
+{
+ ETERM *tl;
+
+ if (!ep) return NULL;
+ /* ASSERT(ep != NULL); */
+
+ if (ERL_TYPE(ep) != ERL_LIST) {
+ return (ETERM *) NULL;
+ }
+
+ tl = TAIL(ep);
+ ERL_COUNT(tl)++;
+ return tl;
+}
+
+/*
+ * Create a LIST from an array of elements. Note that
+ * we create it from the last element in the array to
+ * the first. Also, note that we decrement the reference
+ * counter for each member in the list but the first one.
+ * This is done because of the use of erl_cons.
+ */
+
+ETERM *erl_mk_list (ETERM **arr, int size)
+{
+ ETERM *ep;
+ int i;
+
+ if ((!arr) || (size < 0)) return NULL;
+ for (i=0; i<size; i++) if (!arr[i]) return NULL;
+
+ /* ASSERT(arr != NULL); */
+ ep = erl_mk_empty_list();
+ if (size > 0) {
+ ERL_COUNT(ep)--;
+ }
+
+ for (i = size-1; i >= 0; i--) {
+ /* ASSERT(arr[i] != NULL); */
+ ep = erl_cons(arr[i], ep);
+ if (i > 0)
+ ERL_COUNT(ep)--; /* Internal reference */
+ }
+ return ep;
+}
+
+/*
+ * Create an empty VARIABLE.
+ */
+ETERM *erl_mk_var(const char *s)
+{
+ ETERM *ep;
+
+ if (!s) return NULL;
+
+ /* ASSERT(s != NULL); */
+
+ ep = erl_alloc_eterm(ERL_VARIABLE);
+ ERL_COUNT(ep) = 1;
+ ERL_VAR_LEN(ep) = strlen(s);
+ if ((ERL_VAR_NAME(ep) = strsave(s)) == NULL)
+ {
+ erl_free_term(ep);
+ erl_errno = ENOMEM;
+ return NULL;
+ }
+ ERL_VAR_VALUE(ep) = (ETERM *) NULL;
+ return ep;
+}
+
+/*
+ * Return the CONTENT of a VARIABLE with NAME.
+ * If the content is non-nil then bump its
+ * reference counter.
+ */
+ETERM *erl_var_content (const ETERM *ep, const char *name)
+{
+ int i;
+ ETERM *vp;
+
+ if ((!ep) || (!name)) return NULL;
+
+ /* ASSERT(ep != NULL); */
+
+ switch(ERL_TYPE(ep))
+ {
+ case ERL_VARIABLE:
+ if (strcmp(ERL_VAR_NAME(ep), name) == 0) {
+ if ((vp = ERL_VAR_VALUE(ep)) != NULL) {
+ ERL_COUNT(vp)++;
+ return vp;
+ }
+ }
+ break;
+
+ case ERL_LIST:
+ while (ep && (ERL_TYPE(ep) != ERL_EMPTY_LIST)) {
+ if ((vp = erl_var_content(HEAD(ep), name))) return vp;
+ ep = TAIL(ep);
+ }
+ break;
+
+ case ERL_TUPLE:
+ for (i=0; i < ERL_TUPLE_SIZE(ep); i++)
+ if ((vp = erl_var_content(ERL_TUPLE_ELEMENT(ep, i), name)))
+ {
+ return vp;
+ }
+ break;
+
+ default:
+ /* variables can't occur in other types */
+ break;
+ }
+
+ /* nothing found ! */
+ return NULL;
+}
+
+/*
+ * Return the SIZE of a TUPLE or a BINARY.
+ * At failure -1 is returned.
+ */
+int erl_size (const ETERM *ep)
+{
+ if (!ep) return -1;
+
+ /* ASSERT(ep != NULL); */
+
+ switch (ERL_TYPE(ep)) {
+ case ERL_TUPLE:
+ return ERL_TUPLE_SIZE(ep);
+
+ case ERL_BINARY:
+ return ERL_BIN_SIZE(ep);
+
+ default:
+ return -1;
+
+ }
+}
+
+/*
+ * Return the LENGTH of a LIST.
+ * At failure -1 is returned (this include non-proper lists like [a|b]).
+ */
+int erl_length(const ETERM *ep)
+{
+ int n = 0;
+
+ if (!ep) return -1;
+ /* ASSERT(ep != NULL); */
+
+ while (ERL_TYPE(ep) == ERL_LIST) {
+ n++;
+ ep = TAIL(ep);
+ }
+
+ if (!ERL_IS_EMPTY_LIST(ep)) return -1;
+
+ return n;
+}
+
+
+/***********************************************************************
+ * I o l i s t f u n c t i o n s
+ *
+ * The following functions handles I/O lists.
+ *
+ * Informally, an I/O list is a deep list of characters and binaries,
+ * which can be sent to an Erlang port.
+ *
+ * Formally, in BNF, an I/O list is defined as:
+ *
+ * iolist ::= []
+ * | Binary
+ * | [iohead | iolist]
+ * ;
+ *
+ * iohead ::= Binary
+ * | Byte (integer in the range [0..255])
+ * | iolist
+ * ;
+ *
+ * Note that versions of Erlang/OTP prior to R2 had a slightly more
+ * restricted definition of I/O lists, in that the tail of a an I/O list
+ * was not allowed to be a binary. The erl_interface functions
+ * for I/O lists follows the more liberal rules described by the BNF
+ * description above.
+ ***********************************************************************/
+
+/*
+ * This function converts an I/O list to a '\0' terminated C string.
+ * The I/O list must not contain any occurrences of the integer 0.
+ *
+ * The string will be in memory allocated by erl_malloc(). It is the
+ * responsibility of the caller to eventually call erl_free() to free
+ * the memory.
+ *
+ * Returns: NULL if the list was not an I/O list or contained
+ * the integer 0, otherwise a pointer to '\0' terminated string.
+ */
+
+char* erl_iolist_to_string(const ETERM* term)
+{
+ ETERM* bin;
+
+ if ((bin = erl_iolist_to_binary(term)) == NULL) {
+ return NULL;
+ } else {
+ char* result = NULL;
+
+ if (memchr(ERL_BIN_PTR(bin), '\0', ERL_BIN_SIZE(bin)) == NULL) {
+ result = (char *) erl_malloc(ERL_BIN_SIZE(bin)+1);
+ memcpy(result, ERL_BIN_PTR(bin), ERL_BIN_SIZE(bin));
+ result[ERL_BIN_SIZE(bin)] = '\0';
+ }
+ erl_free_term(bin);
+ return result;
+ }
+}
+
+/*
+ * This function converts an I/O list to a binary term.
+ *
+ * Returns: NULL if the list was not an I/O list, otherwise
+ * an ETERM pointer pointing to a binary term.
+ */
+
+ETERM *erl_iolist_to_binary (const ETERM* term)
+{
+ ETERM *dest;
+ int size;
+ char* ptr;
+
+ if (!term) return NULL;
+ /* ASSERT(term != NULL); */
+
+ /*
+ * Verify that the term is an I/O list and get its length.
+ */
+
+ size = erl_iolist_length(term);
+ if (size == -1) {
+ return NULL;
+ }
+
+ /*
+ * Allocate the binary and copy the contents of the I/O list into it.
+ */
+
+ dest = erl_alloc_eterm(ERL_BINARY);
+ ERL_COUNT(dest) = 1;
+ ERL_BIN_SIZE(dest) = size;
+ ptr = (char *)erl_malloc(size);
+ ERL_BIN_PTR(dest) = (unsigned char *)ptr;
+ iolist_to_buf(term, &ptr);
+
+ /*
+ * If ptr doesn't point exactly one byte beyond the end of the
+ * binary, something must be seriously wrong.
+ */
+
+ if (ERL_BIN_PTR(dest) + size != (unsigned char *) ptr) return NULL;
+ /* ASSERT(ERL_BIN_PTR(dest) + size == (unsigned char *) ptr); */
+
+ return dest;
+}
+
+/*
+ * Returns the length of an I/O list.
+ *
+ * Returns: -1 if the term if the given term is not a I/O list,
+ * or the length otherwise.
+ */
+
+int erl_iolist_length (const ETERM* term)
+{
+ int len = 0;
+
+ while (ERL_IS_CONS(term)) {
+ ETERM* obj = HEAD(term);
+
+ if (ERL_IS_BYTE(obj)) {
+ len++;
+ } else if (ERL_IS_CONS(obj)) {
+ int i;
+ if ((i = erl_iolist_length(obj)) < 0)
+ return i;
+ len += i;
+ } else if (ERL_IS_BINARY(obj)) {
+ len += ERL_BIN_SIZE(obj);
+ } else if (!ERL_IS_EMPTY_LIST(obj)) {
+ return(-1);
+ }
+ term = TAIL(term);
+ }
+ if (ERL_IS_EMPTY_LIST(term))
+ return len;
+ else if (ERL_IS_BINARY(term))
+ return len + ERL_BIN_SIZE(term);
+ else
+ return -1;
+}
+
+/*
+ * Return a brand NEW COPY of an ETERM.
+ */
+/*
+ * FIXME: Deep (the whole tree) or shallow (just the top term) copy?
+ * The documentation never says, but the code as written below will
+ * make a deep copy. This should be documented.
+ */
+ETERM *erl_copy_term(const ETERM *ep)
+{
+ int i;
+ ETERM *cp;
+
+ if (!ep) return NULL;
+ /* ASSERT(ep != NULL); */
+
+ cp = erl_alloc_eterm(ERL_TYPE(ep));
+ ERL_COUNT(cp) = 1;
+
+ switch(ERL_TYPE(cp)) {
+ case ERL_INTEGER:
+ case ERL_SMALL_BIG:
+ ERL_INT_VALUE(cp) = ERL_INT_VALUE(ep);
+ break;
+ case ERL_U_INTEGER:
+ case ERL_U_SMALL_BIG:
+ ERL_INT_UVALUE(cp) = ERL_INT_UVALUE(ep);
+ break;
+ case ERL_FLOAT:
+ ERL_FLOAT_VALUE(cp) = ERL_FLOAT_VALUE(ep);
+ break;
+ case ERL_ATOM:
+ ERL_ATOM_SIZE(cp) = ERL_ATOM_SIZE(ep);
+ ERL_ATOM_PTR(cp) = strsave(ERL_ATOM_PTR(ep));
+ if (ERL_ATOM_PTR(cp) == NULL)
+ {
+ erl_free_term(cp);
+ erl_errno = ENOMEM;
+ return NULL;
+ }
+ break;
+ case ERL_PID:
+ /* FIXME: First copy the bit pattern, then duplicate the node
+ name and plug in. Somewhat ugly (also done with port and
+ ref below). */
+ memcpy(&cp->uval.pidval, &ep->uval.pidval, sizeof(Erl_Pid));
+ ERL_PID_NODE(cp) = strsave(ERL_PID_NODE(ep));
+ ERL_COUNT(cp) = 1;
+ break;
+ case ERL_PORT:
+ memcpy(&cp->uval.portval, &ep->uval.portval, sizeof(Erl_Port));
+ ERL_PORT_NODE(cp) = strsave(ERL_PORT_NODE(ep));
+ ERL_COUNT(cp) = 1;
+ break;
+ case ERL_REF:
+ memcpy(&cp->uval.refval, &ep->uval.refval, sizeof(Erl_Ref));
+ ERL_REF_NODE(cp) = strsave(ERL_REF_NODE(ep));
+ ERL_COUNT(cp) = 1;
+ break;
+ case ERL_LIST:
+ HEAD(cp) = erl_copy_term(HEAD(ep));
+ TAIL(cp) = erl_copy_term(TAIL(ep));
+ break;
+ case ERL_EMPTY_LIST:
+ break;
+ case ERL_TUPLE:
+ i = ERL_TUPLE_SIZE(cp) = ERL_TUPLE_SIZE(ep);
+ ERL_TUPLE_ELEMS(cp) = (ETERM**) erl_malloc(i * sizeof(ETERM*));
+ for(i=0; i < ERL_TUPLE_SIZE(ep); i++)
+ ERL_TUPLE_ELEMENT(cp,i) = erl_copy_term(ERL_TUPLE_ELEMENT(ep, i));
+ break;
+ case ERL_BINARY:
+ ERL_BIN_SIZE(cp) = ERL_BIN_SIZE(ep);
+ ERL_BIN_PTR(cp) = (unsigned char *) erl_malloc(ERL_BIN_SIZE(ep));
+ memcpy(ERL_BIN_PTR(cp), ERL_BIN_PTR(ep), ERL_BIN_SIZE(ep));
+ break;
+ case ERL_FUNCTION:
+ i = ERL_CLOSURE_SIZE(cp) = ERL_CLOSURE_SIZE(ep);
+ ERL_FUN_ARITY(cp) = ERL_FUN_ARITY(ep);
+ ERL_FUN_NEW_INDEX(cp) = ERL_FUN_NEW_INDEX(ep);
+ ERL_FUN_INDEX(cp) = erl_copy_term(ERL_FUN_INDEX(ep));
+ ERL_FUN_UNIQ(cp) = erl_copy_term(ERL_FUN_UNIQ(ep));
+ ERL_FUN_CREATOR(cp) = erl_copy_term(ERL_FUN_CREATOR(ep));
+ ERL_FUN_MODULE(cp) = erl_copy_term(ERL_FUN_MODULE(ep));
+ memcpy(ERL_FUN_MD5(cp), ERL_FUN_MD5(ep), sizeof(ERL_FUN_MD5(ep)));
+ ERL_CLOSURE(cp) = (ETERM**) erl_malloc(i * sizeof(ETERM*));
+ for(i=0; i < ERL_CLOSURE_SIZE(ep); i++)
+ ERL_CLOSURE_ELEMENT(cp,i) =
+ erl_copy_term(ERL_CLOSURE_ELEMENT(ep, i));
+ break;
+ default:
+ erl_err_msg("<ERROR> erl_copy_term: wrong type encountered !");
+ erl_free_term(cp);
+ return (ETERM *) NULL;
+ }
+
+ return cp;
+}
+
+#ifndef SILENT
+
+static int print_string(FILE* fp, const ETERM* ep);
+static int is_printable_list(const ETERM* term);
+
+/*
+ * PRINT out an ETERM.
+ */
+
+int erl_print_term(FILE *fp, const ETERM *ep)
+{
+ int j,i,doquote;
+ int ch_written = 0; /* counter of written chars */
+
+ if ((!fp) || (!ep)) return 0;
+ /* ASSERT(ep != NULL); */
+
+ j = i = doquote = 0;
+ switch(ERL_TYPE(ep))
+ {
+ case ERL_ATOM:
+ /* FIXME: what if some weird locale is in use? */
+ if (!islower((int)ERL_ATOM_PTR(ep)[0]))
+ doquote = 1;
+
+ for (i = 0; !doquote && i < ERL_ATOM_SIZE(ep); i++)
+ {
+ doquote = !(isalnum((int)ERL_ATOM_PTR(ep)[i])
+ || (ERL_ATOM_PTR(ep)[i] == '_'));
+ }
+
+ if (doquote) {
+ putc('\'', fp);
+ ch_written++;
+ }
+ fputs(ERL_ATOM_PTR(ep), fp);
+ ch_written += ERL_ATOM_SIZE(ep);
+ if (doquote) {
+ putc('\'', fp);
+ ch_written++;
+ }
+ break;
+
+ case ERL_VARIABLE:
+ if (!isupper((int)ERL_VAR_NAME(ep)[0])) {
+ doquote = 1;
+ putc('\'', fp);
+ ch_written++;
+ }
+
+ fputs(ERL_VAR_NAME(ep), fp);
+ ch_written += ERL_VAR_LEN(ep);
+
+ if (doquote) {
+ putc('\'', fp);
+ ch_written++;
+ }
+ break;
+
+ case ERL_PID:
+ ch_written += fprintf(fp, "<%s.%d.%d>",
+ ERL_PID_NODE(ep),
+ ERL_PID_NUMBER(ep), ERL_PID_SERIAL(ep));
+ break;
+ case ERL_PORT:
+ ch_written += fprintf(fp, "#Port");
+ break;
+ case ERL_REF:
+ ch_written += fprintf(fp, "#Ref");
+ break;
+ case ERL_EMPTY_LIST:
+ ch_written += fprintf(fp, "[]");
+ break;
+ case ERL_LIST:
+ if (is_printable_list(ep)) {
+ ch_written += print_string(fp, ep);
+ } else {
+ putc('[', fp);
+ ch_written++;
+ while (ERL_IS_CONS(ep)) {
+ ch_written += erl_print_term(fp, HEAD(ep));
+ ep = TAIL(ep);
+ if (ERL_IS_CONS(ep)) {
+ putc(',', fp);
+ ch_written++;
+ }
+ }
+ if (!ERL_IS_EMPTY_LIST(ep)) {
+ putc('|', fp);
+ ch_written++;
+ ch_written += erl_print_term(fp, ep);
+ }
+ putc(']', fp);
+ ch_written++;
+ }
+ break;
+ case ERL_TUPLE:
+ putc('{', fp);
+ ch_written++;
+ for (i=0; i < ERL_TUPLE_SIZE(ep); i++) {
+ ch_written += erl_print_term(fp, ERL_TUPLE_ELEMENT(ep, j++) );
+ if (i != ERL_TUPLE_SIZE(ep)-1) {
+ putc(',', fp);
+ ch_written++;
+ }
+ }
+ putc('}', fp);
+ ch_written++;
+ break;
+ case ERL_BINARY: {
+ int sz = (ERL_BIN_SIZE(ep) > 20) ? 20 : ERL_BIN_SIZE(ep);
+ unsigned char *ptr = ERL_BIN_PTR(ep);
+ ch_written += fprintf(fp, "#Bin<");
+ for (i = 0; i < sz; i++) {
+ putc(ptr[i], fp); ch_written++;
+ }
+ if (sz == 20) ch_written += fprintf(fp, "(%d)....>", ERL_BIN_SIZE(ep)-20);
+ else ch_written += fprintf(fp, ">");
+ break;
+ }
+ case ERL_INTEGER:
+ case ERL_SMALL_BIG:
+ ch_written += fprintf(fp, "%d", ERL_INT_VALUE(ep));
+ break;
+ case ERL_U_INTEGER:
+ case ERL_U_SMALL_BIG:
+ ch_written += fprintf(fp, "%d", ERL_INT_UVALUE(ep));
+ break;
+ case ERL_LONGLONG:
+ case ERL_U_LONGLONG:
+ ch_written += fprintf(fp, "%lld", ERL_LL_UVALUE(ep));
+ break;
+ case ERL_FLOAT:
+ ch_written += fprintf(fp, "%f", ERL_FLOAT_VALUE(ep));
+ break;
+ case ERL_FUNCTION:
+ ch_written += fprintf(fp, "#Fun<");
+ ch_written += erl_print_term(fp, ERL_FUN_MODULE(ep));
+ putc('.', fp);
+ ch_written++;
+ ch_written += erl_print_term(fp, ERL_FUN_INDEX(ep));
+ putc('.', fp);
+ ch_written++;
+ ch_written += erl_print_term(fp, ERL_FUN_UNIQ(ep));
+ putc('>', fp);
+ ch_written++;
+ break;
+ default:
+ ch_written = -10000;
+ erl_err_msg("<ERROR> erl_print_term: Bad type of term !");
+ }
+ return ch_written;
+}
+
+/*
+ * FIXME not done yet....
+ */
+
+#if 0
+
+int erl_sprint_term(char *buf, const ETERM *ep)
+{
+ int j,i,doquote;
+ int ch_written = 0; /* counter of written chars */
+
+ if ((!buf) || (!ep)) return 0;
+ /* ASSERT(ep != NULL); */
+
+ j = i = doquote = 0;
+ switch(ERL_TYPE(ep))
+ {
+ case ERL_ATOM:
+ /* FIXME: what if some weird locale is in use? */
+ if (!islower((int)ERL_ATOM_PTR(ep)[0]))
+ doquote = 1;
+
+ for (i = 0; !doquote && i < ERL_ATOM_SIZE(ep); i++)
+ {
+ doquote = !(isalnum((int)ERL_ATOM_PTR(ep)[i])
+ || (ERL_ATOM_PTR(ep)[i] == '_'));
+ }
+
+ if (doquote) {
+ *buf++ = '\'';
+ ch_written++;
+ }
+ {
+ int len = ERL_ATOM_SIZE(ep);
+ strncpy(buf, ERL_ATOM_PTR(ep), len);
+ buf += len;
+ ch_written += len;
+ }
+ if (doquote) {
+ *buf++ = '\'';
+ ch_written++;
+ }
+ break;
+
+ case ERL_VARIABLE:
+ if (!isupper((int)ERL_VAR_NAME(ep)[0])) {
+ doquote = 1;
+ *buf++ = '\'';
+ ch_written++;
+ }
+ len = ERL_VAR_LEN(ep);
+ strncpy(buf, ERL_VAR_NAME(ep), len);
+ buf += len;
+ ch_written += len;
+
+ if (doquote) {
+ *buf++ = '\'';
+ ch_written++;
+ }
+ break;
+
+ case ERL_PID:
+ len = sprintf(buf, "<%s.%d.%d>",
+ ERL_PID_NODE(ep),
+ ERL_PID_NUMBER(ep), ERL_PID_SERIAL(ep));
+ buf += len;
+ ch_written += len;
+ break;
+ case ERL_PORT:
+ len = sprintf(buf , "#Port");
+ buf += len;
+ ch_written += len;
+ break;
+ case ERL_REF:
+ len = sprintf(buf , "#Ref");
+ buf += len;
+ ch_written += len;
+ break;
+ case ERL_EMPTY_LIST:
+ len = sprintf(buf , "[]");
+ buf += len;
+ ch_written += len;
+ break;
+ case ERL_LIST:
+ if (is_printable_list(ep)) {
+ ch_written += print_string(fp, ep);
+ } else {
+ putc('[', fp);
+ ch_written++;
+ while (ERL_IS_CONS(ep)) {
+ ch_written += erl_sprint_term(fp, HEAD(ep));
+ ep = TAIL(ep);
+ if (ERL_IS_CONS(ep)) {
+ putc(',', fp);
+ ch_written++;
+ }
+ }
+ if (!ERL_IS_EMPTY_LIST(ep)) {
+ putc('|', fp);
+ ch_written++;
+ ch_written += erl_sprint_term(fp, ep);
+ }
+ putc(']', fp);
+ ch_written++;
+ }
+ break;
+ case ERL_TUPLE:
+ putc('{', fp);
+ ch_written++;
+ for (i=0; i < ERL_TUPLE_SIZE(ep); i++) {
+ ch_written += erl_sprint_term(fp, ERL_TUPLE_ELEMENT(ep, j++) );
+ if (i != ERL_TUPLE_SIZE(ep)-1) {
+ putc(',', fp);
+ ch_written++;
+ }
+ }
+ putc('}', fp);
+ ch_written++;
+ break;
+ case ERL_BINARY:
+ len = sprintf(buf , "#Bin");
+ buf += len;
+ ch_written += len;
+ break;
+ case ERL_INTEGER:
+ case ERL_SMALL_BIG:
+ len = sprintf(buf , "%d", ERL_INT_VALUE(ep));
+ buf += len;
+ ch_written += len;
+ break;
+ case ERL_U_INTEGER:
+ case ERL_U_SMALL_BIG:
+ len = sprintf(buf , "%d", ERL_INT_UVALUE(ep));
+ buf += len;
+ ch_written += len;
+ break;
+ case ERL_FLOAT:
+ len = sprintf(buf , "%f", ERL_FLOAT_VALUE(ep));
+ buf += len;
+ ch_written += len;
+ break;
+ case ERL_FUNCTION:
+ len = sprintf(buf , "#Fun<");
+ buf += len;
+ ch_written += len;
+ ch_written += erl_sprint_term(fp, ERL_FUN_MODULE(ep));
+ putc('.', fp);
+ ch_written++;
+ ch_written += erl_sprint_term(fp, ERL_FUN_INDEX(ep));
+ putc('.', fp);
+ ch_written++;
+ ch_written += erl_sprint_term(fp, ERL_FUN_UNIQ(ep));
+ putc('>', fp);
+ ch_written++;
+ break;
+ default:
+ ch_written = -10000;
+ erl_err_msg("<ERROR> erl_sprint_term: Bad type of term !");
+ }
+ return ch_written;
+}
+#endif
+
+static int print_string(FILE* fp, const ETERM* ep)
+{
+ int ch_written = 0; /* counter of written chars */
+
+ putc('"', fp);
+ ch_written++;
+ while (ERL_IS_CONS(ep)) {
+ int c = ERL_INT_VALUE(HEAD(ep));
+
+ if (c >= ' ') {
+ putc(c, fp);
+ ch_written++;
+ }
+ else {
+ switch (c) {
+ case '\n': fputs("\\n", fp); ch_written += 2; break;
+ case '\r': fputs("\\r", fp); ch_written += 2; break;
+ case '\t': fputs("\\t", fp); ch_written += 2; break;
+ case '\v': fputs("\\v", fp); ch_written += 2; break;
+ case '\b': fputs("\\b", fp); ch_written += 2; break;
+ case '\f': fputs("\\f", fp); ch_written += 2; break;
+ break;
+ default:
+ ch_written += fprintf(fp, "\\%o", c);
+ break;
+ }
+ }
+ ep = TAIL(ep);
+ }
+ putc('"', fp);
+ ch_written++;
+ return ch_written;
+}
+
+/*
+ * Returns 1 if term is a list of printable character, otherwise 0.
+ */
+
+static int is_printable_list(const ETERM* term)
+{
+ while (ERL_TYPE(term) == ERL_LIST) {
+ ETERM* head = HEAD(term);
+
+ if (!ERL_IS_BYTE(head)) {
+ return 0;
+ }
+ if (ERL_INT_VALUE(head) < ' ') {
+ switch (ERL_INT_VALUE(head)) {
+ case '\n':
+ case '\r':
+ case '\t':
+ case '\v':
+ case '\b':
+ case '\f':
+ break;
+ default:
+ return 0;
+ }
+ }
+ term = TAIL(term);
+ }
+
+ return ERL_IS_EMPTY_LIST(term);
+}
+
+#endif
+
+/*
+ * Retrieves the bytes from an I/O list and copy into a buffer.
+ *
+ * NOTE! It is the responsibility of the caller to ensure that
+ * that the buffer is big enough (typically by calling
+ * erl_iolist_length()), and that the term is an I/O list.
+ *
+ * ETERM* term; Term to convert to bytes.
+ * char** bufp; Pointer to pointer to buffer
+ * where the bytes should be stored.
+ * On return, the pointer will point beyond
+ * the last byte stored.
+ */
+
+static void iolist_to_buf(const ETERM* term, char** bufp)
+{
+ char* dest = *bufp;
+
+ while (ERL_IS_CONS(term)) {
+ ETERM* obj = HEAD(term);
+
+ if (ERL_IS_BYTE(obj)) {
+ *dest++ = ERL_INT_VALUE(obj);
+ } else if (ERL_IS_CONS(obj)) {
+ iolist_to_buf(obj, &dest);
+ } else if (ERL_IS_BINARY(obj)) {
+ memcpy(dest, ERL_BIN_PTR(obj), ERL_BIN_SIZE(obj));
+ dest += ERL_BIN_SIZE(obj);
+ } else {
+ /*
+ * Types have been checked by caller.
+ */
+ if (!ERL_IS_EMPTY_LIST(obj)) return;
+ /* ASSERT(ERL_IS_EMPTY_LIST(obj)); */
+ }
+ term = TAIL(term);
+ }
+ if (ERL_IS_BINARY(term)) {
+ memcpy(dest, ERL_BIN_PTR(term), ERL_BIN_SIZE(term));
+ dest += ERL_BIN_SIZE(term);
+ } else {
+ /*
+ * Types have been checked by caller.
+ */
+ if (!ERL_IS_EMPTY_LIST(term)) return;
+ /* ASSERT(ERL_IS_EMPTY_LIST(term));*/
+ }
+ *bufp = dest;
+}
+
+static char* strsave(const char *src)
+{
+ char * dest = malloc(strlen(src)+1);
+
+ if (dest != NULL)
+ strcpy(dest, src);
+ return dest;
+}
+
+
+/*
+ * Local Variables:
+ * compile-command: "cd ..; ERL_TOP=/clearcase/otp/erts make -k"
+ * End:
+ */
diff --git a/lib/erl_interface/src/legacy/erl_eterm.h b/lib/erl_interface/src/legacy/erl_eterm.h
new file mode 100644
index 0000000000..41b008f04f
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_eterm.h
@@ -0,0 +1,61 @@
+/*
+ * %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%
+ */
+#ifndef _ERL_ETERM_H
+#define _ERL_ETERM_H
+
+#ifndef SILENT
+#include <stdio.h>
+#endif
+
+#include "portability.h"
+
+#define ERL_MAX_COUNT 0xffffff
+#define ERL_MAX ((1 << 27)-1)
+#define ERL_MIN -(1 << 27)
+
+/* FIXME should this be documented and in erl_interface.h ??? */
+#define ERL_BIG_ARITY(x) ((x)->uval.bigval.arity)
+#define ERL_BIG_IS_NEG(x) ((x)->uval.bigval.is_neg)
+#define ERL_BIG_DIGITS(x) ((x)->uval.bigval.digits)
+#define ERL_BIG_DIGIT(x,i) (ERL_BIG_DIGITS(x)[(i)])
+
+/*
+ * Typing checking macros.
+ */
+
+/* FIXME should this be documented and in erl_interface.h ??? */
+#define ERL_IS_DEFINED(x) (ERL_TYPE(x) != 0)
+#define ERL_IS_COMPOUND(x) (ERL_TYPE(x) & ERL_COMPOUND)
+#define ERL_IS_FUNCTION(x) (ERL_TYPE(x) == ERL_FUNCTION)
+#define ERL_IS_BIG(x) (ERL_TYPE(x) == ERL_BIG)
+
+
+typedef struct _heapmark {
+ unsigned long mark; /* id */
+ int size; /* size of buffer */
+ Erl_Heap *base; /* points to start of buffer */
+ Erl_Heap *cur; /* points into buffer */
+ struct _heapmark *prev; /* previous heapmark */
+} Erl_HeapMark;
+
+
+ETERM * __erl_mk_reference(const char *, size_t, unsigned int n[], unsigned char);
+int erl_current_fix_desc(void);
+
+#endif /* _ERL_ETERM_H */
diff --git a/lib/erl_interface/src/legacy/erl_fix_alloc.c b/lib/erl_interface/src/legacy/erl_fix_alloc.c
new file mode 100644
index 0000000000..20f3024e41
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_fix_alloc.c
@@ -0,0 +1,193 @@
+/*
+ * %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%
+ */
+/*
+ * Function: General purpose Memory allocator for fixed block
+ * size objects. This allocater is at least an order of
+ * magnitude faster than malloc().
+ */
+#include "eidef.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ei_locking.h"
+#include "erl_interface.h"
+#include "erl_error.h"
+#include "erl_malloc.h"
+#include "erl_fix_alloc.h"
+#include "erl_eterm.h"
+
+#define WIPE_CHAR ((char)0xaa) /* 10101010 */
+
+/* the freelist is a singly linked list of these */
+/* i.e. the user structure and a link pointer */
+struct fix_block {
+ ETERM term;
+ struct fix_block *next;
+ int free;
+};
+
+/* this is a struct just to keep namespace pollution low on VxWorks */
+struct eterm_stateinfo {
+ struct fix_block *freelist;
+ unsigned long freed;
+ unsigned long allocated;
+#ifdef _REENTRANT
+ ei_mutex_t *lock;
+#endif /* _REENTRANT */
+};
+/* FIXME problem for threaded ? */
+static struct eterm_stateinfo *erl_eterm_state=NULL;
+
+
+int erl_init_eterm_alloc (void)
+{
+#if defined(PURIFY) && defined (DEBUG)
+ fprintf(stderr,"erl_fix_alloc() compiled for Purify - using \"real\" malloc()");
+#endif
+
+ erl_eterm_state = malloc(sizeof(*erl_eterm_state));
+ if (erl_eterm_state == NULL) goto err1;
+
+ erl_eterm_state->freelist = NULL;
+ erl_eterm_state->freed = 0;
+ erl_eterm_state->allocated = 0;
+#ifdef _REENTRANT
+ erl_eterm_state->lock = ei_mutex_create();
+ if (erl_eterm_state->lock == NULL) goto err2;
+#endif /* _REENTRANT */
+
+ return 1;
+
+ /* Error cleanup */
+#ifdef _REENTRANT
+ err2:
+ /* FIXME ENOMEM is not what went wrong... */
+ free(erl_eterm_state);
+#endif /* _REENTRANT */
+ err1:
+ erl_errno = ENOMEM;
+ return 0;
+}
+
+/* get an eterm, from the freelist if possible or from malloc() */
+void *erl_eterm_alloc (void)
+{
+#ifdef PURIFY
+ ETERM *p;
+
+ if ((p = malloc(sizeof(*p)))) {
+ memset(p, WIPE_CHAR, sizeof(*p));
+ }
+ return p;
+#else
+ struct fix_block *b;
+
+#ifdef _REENTRANT
+ ei_mutex_lock(erl_eterm_state->lock, 0);
+#endif /* _REENTRANT */
+
+ /* try to pop block from head of freelist */
+ if ((b = erl_eterm_state->freelist) != NULL) {
+ erl_eterm_state->freelist = b->next;
+ erl_eterm_state->freed--;
+ } else if ((b = malloc(sizeof(*b))) == NULL) {
+ erl_errno = ENOMEM;
+ }
+ erl_eterm_state->allocated++;
+ b->free = 0;
+ b->next = NULL;
+#ifdef _REENTRANT
+ ei_mutex_unlock(erl_eterm_state->lock);
+#endif /* _REENTRANT */
+ return (void *) &b->term;
+#endif /* !PURIFY */
+}
+
+/* free an eterm back to the freelist */
+void erl_eterm_free(void *p)
+{
+#ifdef PURIFY
+ if (p) {
+ memset(p, WIPE_CHAR, sizeof(ETERM));
+ }
+ free(p);
+#else
+ struct fix_block *b = p;
+
+ if (b) {
+ if (b->free) {
+#ifdef DEBUG
+ fprintf(stderr,"erl_eterm_free: attempt to free already freed block %p\n",b);
+#endif
+ return;
+ }
+
+#ifdef _REENTRANT
+ ei_mutex_lock(erl_eterm_state->lock,0);
+#endif /* _REENTRANT */
+ b->free = 1;
+ b->next = erl_eterm_state->freelist;
+ erl_eterm_state->freelist = b;
+ erl_eterm_state->freed++;
+ erl_eterm_state->allocated--;
+#ifdef _REENTRANT
+ ei_mutex_unlock(erl_eterm_state->lock);
+#endif /* _REENTRANT */
+ }
+#endif /* !PURIFY */
+}
+
+/* really free the freelist */
+void erl_eterm_release (void)
+{
+#if !defined(PURIFY)
+ struct fix_block *b;
+
+#ifdef _REENTRANT
+ ei_mutex_lock(erl_eterm_state->lock,0);
+#endif /* _REENTRANT */
+ {
+ while (erl_eterm_state->freelist != NULL) {
+ b = erl_eterm_state->freelist;
+ erl_eterm_state->freelist = b->next;
+ free(b);
+ erl_eterm_state->freed--;
+ }
+ }
+#ifdef _REENTRANT
+ ei_mutex_unlock(erl_eterm_state->lock);
+#endif /* _REENTRANT */
+#endif /* !PURIFY */
+}
+
+void erl_eterm_statistics (unsigned long *allocd, unsigned long *freed)
+{
+ if (allocd) *allocd = erl_eterm_state->allocated;
+ if (freed) *freed = erl_eterm_state->freed;
+
+ return;
+}
+
+
+/*
+ * Local Variables:
+ * compile-command: "cd ..; ERL_TOP=/clearcase/otp/erts make -k"
+ * End:
+ */
diff --git a/lib/erl_interface/src/legacy/erl_fix_alloc.h b/lib/erl_interface/src/legacy/erl_fix_alloc.h
new file mode 100644
index 0000000000..16d2f4217a
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_fix_alloc.h
@@ -0,0 +1,26 @@
+/*
+ * %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%
+ */
+#ifndef _ERL_FIX_ALLOC_H
+#define _ERL_FIX_ALLOC_H
+
+int erl_init_eterm_alloc(void);
+void erl_eterm_free(void*);
+void *erl_eterm_alloc(void);
+
+#endif /* _ERL_FIX_ALLOC_H */
diff --git a/lib/erl_interface/src/legacy/erl_format.c b/lib/erl_interface/src/legacy/erl_format.c
new file mode 100644
index 0000000000..9848e9296a
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_format.c
@@ -0,0 +1,729 @@
+/*
+ * %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%
+ */
+/*
+ * Function: Provides two primitives: erl_format to build
+ * Erlang terms in an easy way, and erl_match to perform
+ * pattern match similar to what is done in Erlang.
+ *
+ */
+
+#include "eidef.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef VRTX
+#define __READY_EXTENSIONS__
+#include <errno.h>
+#endif
+#include "erl_interface.h"
+#include "erl_eterm.h"
+#include "erl_malloc.h"
+#include "erl_error.h"
+#include "erl_internal.h"
+
+#define ERL_TRUE 1
+#define ERL_FALSE 0
+#define ERL_OK 0
+#define ERL_FORMAT_ERROR -1
+
+#define ERL_MAX_ENTRIES 255 /* Max entries in a tuple/list term */
+#define ERL_MAX_NAME_LENGTH 255 /* Max length of variable names */
+
+#define PRINT(t) \
+{ \
+ print_term(stderr,t); \
+ fprintf(stderr,"\n"); \
+ }
+
+
+typedef struct lvar {
+ ETERM *var;
+ struct lvar *next;
+} lvar;
+
+
+/* Forward */
+static ETERM *eformat(char**, va_list*);
+static int ematch(ETERM*, ETERM*);
+
+/* FIXME not thread safe */
+struct _ef {
+ lvar *chain; /* Chain of local variables */
+ lvar *idle; /* Idle list of lvar's */
+} ef;
+
+/* Find local variable in term.
+ */
+static ETERM *find_lvar(char *name)
+{
+ lvar *tmp=ef.chain;
+
+ while (tmp != NULL) {
+ if (strcmp(tmp->var->uval.vval.name,name) == 0)
+ return tmp->var->uval.vval.v;
+ tmp = tmp->next;
+ }
+ return (ETERM *) NULL;
+
+} /* find_lvar */
+
+static void lvar_free(lvar *lv)
+{
+ lvar *tmp=ef.chain;
+
+ /* Link in the chain into the idle list */
+ if (ef.idle == NULL)
+ ef.idle = lv;
+ else {
+ tmp = ef.idle;
+ while (tmp->next != NULL)
+ tmp = tmp->next;
+ tmp->next = lv;
+ }
+
+
+ /* Clear out the variable information */
+ tmp = lv;
+ while (tmp != NULL) {
+ tmp->var = (ETERM *) NULL;
+ tmp = tmp->next;
+ }
+
+} /* lvar_free */
+
+static lvar *lvar_alloc(void)
+{
+ lvar *tmp;
+
+ if ((tmp = ef.idle) == NULL) {
+ tmp = (lvar *) malloc(sizeof(lvar)); /* FIXME check result */
+ }
+ else {
+ tmp = ef.idle;
+ ef.idle = tmp->next;
+ }
+ return tmp;
+
+} /* lvar_alloc */
+
+static void undo_bindings(void)
+{
+ lvar *tmp=ef.chain;
+
+ while (tmp != NULL) {
+ erl_free_term(tmp->var->uval.vval.v);
+ tmp->var->uval.vval.v = (ETERM *) NULL;
+ tmp = tmp->next;
+ }
+
+} /* undo_bindings */
+
+static void release_chain(void)
+{
+
+ lvar_free(ef.chain);
+ ef.chain = (lvar *) NULL;
+
+} /* release_chain */
+
+static void add_lvar(ETERM *t)
+{
+ lvar *lv;
+
+ lv = lvar_alloc();
+ lv->var = t;
+ lv->next = ef.chain;
+ ef.chain = lv;
+
+} /* add_lvar */
+
+static char *pvariable(char **fmt, char *buf)
+{
+ char *start=*fmt;
+ char c;
+ int len;
+
+ while (1) {
+ c = *(*fmt)++;
+ if (isalnum((int) c) || (c == '_'))
+ continue;
+ else
+ break;
+ }
+ (*fmt)--;
+ len = *fmt - start;
+ memcpy(buf, start, len);
+ buf[len] = 0;
+
+ return buf;
+
+} /* pvariable */
+
+static char *patom(char **fmt, char *buf)
+{
+ char *start=*fmt;
+ char c;
+ int len;
+
+ while (1) {
+ c = *(*fmt)++;
+ if (isalnum((int) c) || (c == '_') || (c == '@'))
+ continue;
+ else
+ break;
+ }
+ (*fmt)--;
+ len = *fmt - start;
+ memcpy(buf, start, len);
+ buf[len] = 0;
+
+ return buf;
+
+} /* patom */
+
+/* Check if integer or float
+ */
+static char *pdigit(char **fmt, char *buf)
+{
+ char *start=*fmt;
+ char c;
+ int len,dotp=0;
+
+ while (1) {
+ c = *(*fmt)++;
+ if (isdigit((int) c))
+ continue;
+ else if (!dotp && (c == '.')) {
+ dotp = 1;
+ continue;
+ }
+ else
+ break;
+ }
+ (*fmt)--;
+ len = *fmt - start;
+ memcpy(buf, start, len);
+ buf[len] = 0;
+
+ return buf;
+
+} /* pdigit */
+
+static char *pstring(char **fmt, char *buf)
+{
+ char *start=++(*fmt); /* skip first quote */
+ char c;
+ int len;
+
+ while (1) {
+ c = *(*fmt)++;
+ if (c == '"') {
+ if (*((*fmt)-1) == '\\')
+ continue;
+ else
+ break;
+ } else
+ continue;
+ }
+ len = *fmt - 1 - start; /* skip last quote */
+ memcpy(buf, start, len);
+ buf[len] = 0;
+
+ return buf;
+
+} /* pstring */
+
+static char *pquotedatom(char **fmt, char *buf)
+{
+ char *start=++(*fmt); /* skip first quote */
+ char c;
+ int len;
+
+ while (1) {
+ c = *(*fmt)++;
+ if (c == '\'') {
+ if (*((*fmt)-1) == '\\')
+ continue;
+ else
+ break;
+ } else
+ continue;
+ }
+ len = *fmt - 1 - start; /* skip last quote */
+ memcpy(buf, start, len);
+ buf[len] = 0;
+
+ return buf;
+
+} /* pquotedatom */
+
+
+/*
+ * The format letters are:
+ * w - Any Erlang term
+ * a - An Atom
+ * b - A Binary
+ * s - A String
+ * i - An Integer
+ * f - A Float (double)
+ */
+static int pformat(char **fmt, va_list *pap, ETERM *v[], int size)
+{
+ int rc=ERL_OK;
+
+ /* this next section hacked to remove the va_arg calls */
+ switch (*(*fmt)++) {
+
+ case 'w':
+ v[size] = va_arg(*pap, ETERM*);
+ ERL_COUNT(v[size])++;
+ break;
+
+ case 'a':
+ v[size] = erl_mk_atom(va_arg(*pap, char *));
+ break;
+
+ case 's':
+ v[size] = erl_mk_string(va_arg(*pap, char *));
+ break;
+
+ case 'i':
+ v[size] = erl_mk_int(va_arg(*pap, int));
+ break;
+
+ case 'f':
+ v[size] = erl_mk_float(va_arg(*pap, double));
+ break;
+
+ case 'b': {
+ char *sarg = va_arg(*pap, char *);
+ v[size] = erl_mk_binary(sarg, strlen(sarg));
+ break;
+ }
+
+ default:
+ rc = ERL_FORMAT_ERROR;
+ break;
+ }
+
+ return rc;
+
+} /* pformat */
+
+static int ptuple(char **fmt, va_list *pap, ETERM *v[], int size)
+{
+ int res=ERL_FORMAT_ERROR;
+
+ switch (*(*fmt)++) {
+
+ case '}':
+ res = size;
+ break;
+
+ case ',':
+ res = ptuple(fmt, pap, v, size);
+ break;
+
+ case '~':
+
+ if (pformat(fmt, pap, v, size) == ERL_OK)
+ res = ptuple(fmt, pap, v, ++size);
+ else
+ erl_err_msg("ptuple(1): Wrong format sequence !");
+ break;
+
+ case ' ':
+ return ptuple(fmt, pap, v, size);
+ break;
+
+ default: {
+ (*fmt)--;
+ if ((v[size++] = eformat(fmt, pap)) != (ETERM *) NULL)
+ res = ptuple(fmt, pap, v, size);
+ break;
+
+ /*
+ if (isupper(**fmt)) {
+ v[size++] = erl_mk_var(pvariable(fmt, wbuf));
+ res = ptuple(fmt, pap, v, size);
+ }
+ else if ((v[size++] = eformat(fmt, pap)) != (ETERM *) NULL)
+ res = ptuple(fmt, pap, v, size);
+ break;
+ */
+ }
+
+ } /* switch */
+
+ return res;
+
+} /* ptuple */
+
+
+static int plist(char **fmt, va_list *pap, ETERM *v[], int size)
+{
+ int res=ERL_FORMAT_ERROR;
+
+ switch (*(*fmt)++) {
+
+ case ']':
+ res = size;
+ break;
+
+ case ',':
+ res = plist(fmt, pap, v, size);
+ break;
+
+ case '~':
+
+ if (pformat(fmt, pap, v, size) == ERL_OK)
+ res = plist(fmt, pap, v, ++size);
+ else
+ erl_err_msg("plist(1): Wrong format sequence !");
+ break;
+
+ case ' ':
+ return plist(fmt, pap, v, size);
+ break;
+
+ default: {
+ (*fmt)--;
+ if ((v[size++] = eformat(fmt, pap)) != (ETERM *) NULL)
+ res = plist(fmt, pap, v, size);
+ break;
+
+ /*
+ if (isupper(**fmt)) {
+ v[size++] = erl_mk_var(pvariable(fmt, wbuf));
+ res = plist(fmt, pap, v, size);
+ }
+ else if ((v[size++] = eformat(fmt, pap)) != (ETERM *) NULL)
+ res = plist(fmt, pap, v, size);
+ break;
+ */
+ }
+
+ } /* switch */
+
+ return res;
+
+} /* plist */
+
+
+static ETERM *eformat(char **fmt, va_list *pap)
+{
+ int size;
+ ETERM *v[ERL_MAX_ENTRIES],*ep;
+
+ switch (*(*fmt)++) {
+ case '{':
+ if ((size = ptuple(fmt, pap , v, 0)) != ERL_FORMAT_ERROR) {
+ ep = erl_mk_tuple(v, size);
+ erl_free_array(v, size);
+ return ep;
+ }
+ else
+ return (ETERM *) NULL;
+ break;
+
+ case '[':
+ if (**fmt == ']') {
+ (*fmt)++;
+ return erl_mk_empty_list();
+ } else if ((size = plist(fmt, pap , v, 0)) != ERL_FORMAT_ERROR) {
+ ep = erl_mk_list(v, size);
+ erl_free_array(v, size);
+ return ep;
+ } else
+ return (ETERM *) NULL;
+ break;
+
+ case '$': /* char-value? */
+ return erl_mk_int((int)(*(*fmt)++));
+ break;
+
+ case '~':
+ if (pformat(fmt, pap, v, 0) == ERL_OK) {
+ ep = erl_copy_term(v[0]);
+ erl_free_term(v[0]);
+ return ep;
+ }
+ break;
+
+ case ' ':
+ return eformat(fmt, pap);
+ break;
+
+ /* handle negative numbers too...
+ * case '-':
+ * {
+ * ETERM *tmp;
+ *
+ * tmp = eformat(fmt,pap);
+ * if (ERL_IS_INTEGER(tmp)) ERL_INT_VALUE(tmp) = -(ERL_INT_VALUE(tmp));
+ * return tmp;
+ * }
+ *
+ *
+ * break;
+ */
+
+ default:
+ {
+ char wbuf[BUFSIZ]; /* now local to this function for reentrancy */
+
+ (*fmt)--;
+ if (islower((int)**fmt)) { /* atom ? */
+ char *atom=patom(fmt, wbuf);
+ return erl_mk_atom(atom);
+ }
+ else if (isupper((int)**fmt) || (**fmt == '_')) {
+ char *var=pvariable(fmt, wbuf);
+ return erl_mk_var(var);
+ }
+ else if (isdigit((int)**fmt)) { /* integer/float ? */
+ char *digit=pdigit(fmt, wbuf);
+ if (strchr(digit,(int) '.') == NULL)
+ return erl_mk_int(atoi((const char *) digit));
+ else
+ return erl_mk_float(atof((const char *) digit));
+ }
+ else if (**fmt == '"') { /* string ? */
+ char *string=pstring(fmt, wbuf);
+ return erl_mk_string(string);
+ }
+ else if (**fmt == '\'') { /* quoted atom ? */
+ char *qatom=pquotedatom(fmt, wbuf);
+ return erl_mk_atom(qatom);
+ }
+ }
+ break;
+
+ }
+
+ erl_err_msg("<ERROR> Syntax error in eformat, char was: %c !", **fmt);
+ return (ETERM *) NULL;
+
+} /* eformat */
+
+
+ETERM *erl_format(char *fmt, ... )
+{
+ ETERM *res=NULL;
+ va_list ap;
+
+ va_start(ap, fmt);
+ res = eformat(&fmt, &ap);
+ va_end(ap);
+
+ return res;
+} /* erl_format */
+
+
+/*
+ * Perform a pattern match between a pattern p and a term t.
+ * As a side effect bind any unbound variables in p.
+ * Return true or false.
+ */
+static int ematch(ETERM *p, ETERM *t)
+{
+ unsigned int type_p;
+ unsigned int type_t;
+ ETERM *tmp;
+
+ /* two NULLs are equal, one is not... */
+ if (!p && !t) return ERL_TRUE;
+ if (!p || !t) return ERL_FALSE;
+ /*
+ * ASSERT(p != NULL);
+ * ASSERT(t != NULL);
+ */
+
+ type_p = ERL_TYPE(p);
+ type_t = ERL_TYPE(t);
+
+ if (type_t == ERL_VARIABLE) {
+ if (t->uval.vval.v == NULL)
+ return ERL_FALSE; /* Can't have an unbound variable here ! */
+ else
+ t = t->uval.vval.v;
+ }
+
+ if (type_p != ERL_VARIABLE && type_p != type_t)
+ return ERL_FALSE;
+
+ switch (type_p) {
+
+ case ERL_ATOM:
+ return p->uval.aval.len == t->uval.aval.len &&
+ memcmp(p->uval.aval.a, t->uval.aval.a, p->uval.aval.len) == 0;
+
+ case ERL_VARIABLE:
+ if (strcmp(p->uval.vval.name, "_") == 0) /* anon. variable */
+ return ERL_TRUE;
+ else if ((tmp = find_lvar(p->uval.vval.name)) != (ETERM *) NULL) {
+ /* v points to NULL in cases like erl_format("{X,X}") for the
+ second variable */
+ if (p->uval.vval.v == NULL)
+ p->uval.vval.v = erl_copy_term(tmp);
+ return ematch(p->uval.vval.v, t);
+ }
+ else {
+ /* check if the variable is bound already */
+ if (p->uval.vval.v != NULL) {
+ if (ematch(p->uval.vval.v, t) == ERL_TRUE ){
+ add_lvar(p);
+ return ERL_TRUE;
+ }
+ else
+ return ERL_FALSE;
+ }
+ else {
+ p->uval.vval.v = erl_copy_term(t);
+ add_lvar(p);
+ return ERL_TRUE;
+ }
+ }
+ break;
+
+ case ERL_PID:
+ if ((strcmp(ERL_PID_NODE(p), ERL_PID_NODE(t)) == 0) &&
+ (ERL_PID_NUMBER(p) == ERL_PID_NUMBER(t)) &&
+ (ERL_PID_SERIAL(p) == ERL_PID_SERIAL(t)) &&
+ (ERL_PID_CREATION(p) == ERL_PID_CREATION(t)))
+ return ERL_TRUE;
+ else
+ return ERL_FALSE;
+ break;
+
+ case ERL_PORT:
+ if ((strcmp(ERL_PORT_NODE(p), ERL_PORT_NODE(t)) == 0) &&
+ (ERL_PORT_NUMBER(p) == ERL_PORT_NUMBER(t)) &&
+ (ERL_PORT_CREATION(p) == ERL_PORT_CREATION(t)))
+ return ERL_TRUE;
+ else
+ return ERL_FALSE;
+ break;
+
+ case ERL_REF: {
+ int i, len;
+
+ if (strcmp(ERL_REF_NODE(p), ERL_REF_NODE(t)) != 0 ||
+ ERL_REF_CREATION(p) != ERL_REF_CREATION(t))
+ return ERL_FALSE;
+
+ /* FIXME: {len=1, n={42}} and {len=3, n={42, 17, 13}} tests equal. */
+ len = ERL_REF_LEN(p);
+ if (len > ERL_REF_LEN(t))
+ len = ERL_REF_LEN(t);
+
+ for (i = 0; i < len; i++)
+ if (ERL_REF_NUMBERS(p)[i] != ERL_REF_NUMBERS(t)[i])
+ return ERL_FALSE;
+
+ return ERL_TRUE;
+ break;
+ }
+
+ case ERL_EMPTY_LIST:
+ return ERL_TRUE;
+
+ case ERL_LIST:
+ while (ERL_IS_CONS(p) && ERL_IS_CONS(t)) {
+ if (ematch(p->uval.lval.head, t->uval.lval.head) == ERL_FALSE)
+ return ERL_FALSE;
+ p = p->uval.lval.tail;
+ t = t ->uval.lval.tail;
+ }
+ return ematch(p, t);
+
+ case ERL_TUPLE:
+ {
+ int i;
+ if (erl_size(p) != erl_size(t))
+ return ERL_FALSE;
+ else {
+ for(i=0; i<erl_size(p); i++)
+ if (ematch(p->uval.tval.elems[i],t->uval.tval.elems[i]) == ERL_FALSE)
+ return ERL_FALSE;
+ return ERL_TRUE;
+ }
+ }
+ break;
+
+ case ERL_BINARY:
+ {
+ int i;
+ if ((i = p->uval.bval.size) != t->uval.bval.size)
+ return ERL_FALSE;
+ else
+ return (memcmp(p->uval.bval.b,t->uval.bval.b,i)==0) ? ERL_TRUE : ERL_FALSE;
+ }
+ break;
+
+ case ERL_INTEGER:
+ return (p->uval.ival.i == t->uval.ival.i) ? ERL_TRUE : ERL_FALSE;
+ break;
+
+ case ERL_SMALL_BIG:
+ case ERL_U_SMALL_BIG:
+ /* This case can't happend since it is impossible
+ * to create a bignum from the C code.
+ */
+ return ERL_FALSE;
+ break;
+
+ case ERL_FLOAT:
+#if defined(VXWORKS) && CPU == PPC860
+ {
+ return (erl_fp_compare((unsigned *)&(p->uval.fval.f),
+ (unsigned *)&(t->uval.fval.f)) == 0)
+ ? ERL_TRUE : ERL_FALSE;
+ }
+#else
+ return (p->uval.fval.f == t->uval.fval.f) ? ERL_TRUE : ERL_FALSE;
+#endif
+ break;
+ default:
+ return ERL_FALSE;
+ break;
+ }
+
+ /* erl_err_msg("ematch: Unknown type == %c\n", type_p); */
+ return ERL_FALSE;
+
+} /* ematch */
+
+
+int erl_match(ETERM *p, ETERM *t)
+{
+ int i;
+
+ if ((i = ematch(p, t)) == ERL_FALSE)
+ undo_bindings();
+ release_chain();
+ return i;
+
+} /* erl_match */
+
+
diff --git a/lib/erl_interface/src/legacy/erl_format.h b/lib/erl_interface/src/legacy/erl_format.h
new file mode 100644
index 0000000000..90801e4892
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_format.h
@@ -0,0 +1,22 @@
+/*
+ * %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%
+ */
+#ifndef _ERL_FORMAT_H
+#define _ERL_FORMAT_H
+
+#endif /* _ERL_FORMAT_H */
diff --git a/lib/erl_interface/src/legacy/erl_global.h b/lib/erl_interface/src/legacy/erl_global.h
new file mode 100644
index 0000000000..ef09eab0b0
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_global.h
@@ -0,0 +1,27 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef _ERL_GLOBAL_H
+#define _ERL_GLOBAL_H
+
+char **erl_global_names(int fd, int *count);
+ETERM *erl_global_whereis(int fd, const char *name, char *node);
+int erl_global_register(int fd, const char *name, ETERM *pid);
+int erl_global_unregister(int fd, const char *name);
+
+#endif /* _ERL_GLOBAL_H */
diff --git a/lib/erl_interface/src/legacy/erl_internal.h b/lib/erl_interface/src/legacy/erl_internal.h
new file mode 100644
index 0000000000..e79c815946
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_internal.h
@@ -0,0 +1,47 @@
+/*
+ * %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%
+ */
+#ifndef _ERL_INTERNAL_H
+#define _ERL_INTERNAL_H
+
+/*
+ * Function: Some useful stuff not to be exported to users.
+ */
+
+#define HEAD(ep) ep->uval.lval.head
+#define TAIL(ep) ep->uval.lval.tail
+#define ERL_NO_REF(x) (ERL_COUNT(x) == 0)
+
+#ifdef DEBUG
+#define ASSERT(e) \
+ if (e) { \
+ ; \
+ } else { \
+ erl_assert_error(#e, __FILE__, __LINE__); \
+ }
+
+extern void erl_assert_error(char* expr, char* file, int line)
+ __attribute__ ((__noreturn__));
+
+#else
+
+#define ASSERT(e)
+
+#endif
+
+#endif /* _ERL_INTERNAL_H */
diff --git a/lib/erl_interface/src/legacy/erl_malloc.c b/lib/erl_interface/src/legacy/erl_malloc.c
new file mode 100644
index 0000000000..f51a6c69b3
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_malloc.c
@@ -0,0 +1,239 @@
+/*
+ * %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%
+ */
+
+#include "eidef.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "erl_interface.h"
+#include "erl_fix_alloc.h"
+#include "erl_malloc.h"
+#include "erl_internal.h"
+#include "erl_eterm.h"
+#include "ei_malloc.h"
+
+void erl_init_malloc(Erl_Heap *hp, long heap_size)
+{
+ erl_init_eterm_alloc();
+} /* erl_init_malloc */
+
+ETERM *erl_alloc_eterm(unsigned char type)
+{
+ ETERM *e;
+
+ /* Use fix size allocator */
+ if (!(e = (ETERM *) erl_eterm_alloc()))
+ erl_err_sys("<ERROR> erl_alloc_eterm: Failed to allocate more memory\n");
+
+ ERL_HEADER(e)->count = 0;
+ ERL_HEADER(e)->type = type;
+ return e;
+
+} /* erl_alloc_eterm */
+
+#define EXTERNAL 1
+#define INTERNAL 0
+#define COMPOUND 1
+#define NOT_COMPOUND 0
+
+static void _erl_free_term (ETERM *ep, int external, int compound);
+
+/*
+ * Free a term, but don't deallocate it until
+ * the reference counter triggers.
+ */
+void erl_free_term(ETERM *ep)
+{
+ _erl_free_term(ep, EXTERNAL, NOT_COMPOUND);
+} /* erl_free_term */
+
+/*
+ * Free a term regardless of its reference
+ * counter value. Use this when you have
+ * built compound terms such as lists or tuples.
+ */
+
+/*
+ * FIXME is this true?!
+ * Tearing down term structures no-matter-what is a horrible idea if
+ * any term happens to be shared (with some other structure or even
+ * with yourself).
+ */
+
+void erl_free_compound (ETERM *ep)
+{
+ _erl_free_term(ep, EXTERNAL, COMPOUND);
+} /* erl_free_compound */
+
+
+/*
+** The actual free'ing is done here in _erl_free_term.
+** It is by nature recursive, but does not recurse
+** on the CDR of a list, which makes it usable for large lists.
+*/
+
+/*
+** Convenience macro, called for variables and lists,
+** avoids deep recursions.
+*/
+#define RESTART(Eterm, External, Compound) \
+do { \
+ ETERM *sep; \
+ sep = (Eterm); \
+ external = (External); \
+ compound = (Compound); \
+ /* Clear header info */ \
+ ERL_TYPE(ep) = ERL_UNDEF; \
+ erl_eterm_free((unsigned int *) ep); \
+ ep = sep; \
+ goto restart; \
+} while(0)
+
+#define FREE_AND_CLEAR(ptr) \
+do { \
+ erl_free(ptr); \
+ (ptr) = NULL; \
+} while (0)
+
+static void _erl_free_term (ETERM *ep, int external, int compound)
+{
+restart:
+ if (ep == NULL)
+ return;
+ if (compound || ERL_NO_REF(ep)) {
+ /* Yes, it's time to *really* free this one ! */
+ switch(ERL_TYPE(ep))
+ {
+ case ERL_ATOM:
+ FREE_AND_CLEAR(ERL_ATOM_PTR(ep));
+ break;
+ case ERL_VARIABLE:
+ FREE_AND_CLEAR(ERL_VAR_NAME(ep));
+ /* Note: It may be unbound ! */
+ if (ERL_VAR_VALUE(ep) != NULL) {
+ ERL_COUNT(ERL_VAR_VALUE(ep))--;
+ /* Cleanup and Restart with the actual value */
+ RESTART(ERL_VAR_VALUE(ep), INTERNAL, compound);
+ }
+ break;
+ case ERL_LIST:
+ if (HEAD(ep)) {
+ ERL_COUNT(HEAD(ep))--;
+ /* FIXME added cast, is this correct? */
+ _erl_free_term((ETERM *)HEAD(ep), INTERNAL, compound);
+ }
+ if (TAIL(ep)) {
+ ERL_COUNT(TAIL(ep))--;
+ /* Clean up and walk on to CDR in list */
+ RESTART(TAIL(ep), INTERNAL, compound);
+ }
+ break;
+ case ERL_TUPLE:
+ {
+ int i;
+ for (i=0; i < ERL_TUPLE_SIZE(ep); i++)
+ if (ERL_TUPLE_ELEMENT(ep, i)) {
+ ERL_COUNT(ERL_TUPLE_ELEMENT(ep, i))--;
+ _erl_free_term(ERL_TUPLE_ELEMENT(ep, i),
+ INTERNAL, compound);
+ }
+ FREE_AND_CLEAR(ERL_TUPLE_ELEMS(ep));
+ }
+ break;
+ case ERL_BINARY:
+ FREE_AND_CLEAR(ERL_BIN_PTR(ep));
+ break;
+ case ERL_PID:
+ FREE_AND_CLEAR(ERL_PID_NODE(ep));
+ break;
+ case ERL_PORT:
+ FREE_AND_CLEAR(ERL_PORT_NODE(ep));
+ break;
+ case ERL_REF:
+ FREE_AND_CLEAR(ERL_REF_NODE(ep));
+ break;
+ case ERL_EMPTY_LIST:
+ case ERL_INTEGER:
+ case ERL_SMALL_BIG:
+ case ERL_U_SMALL_BIG:
+ case ERL_FLOAT:
+ break;
+ case ERL_FUNCTION:
+ {
+ int i;
+
+ _erl_free_term(ERL_FUN_INDEX(ep), INTERNAL, compound);
+ _erl_free_term(ERL_FUN_UNIQ(ep), INTERNAL, compound);
+ _erl_free_term(ERL_FUN_CREATOR(ep), INTERNAL, compound);
+ _erl_free_term(ERL_FUN_MODULE(ep), INTERNAL, compound);
+ if (ERL_CLOSURE(ep) != NULL) {
+ for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++)
+ _erl_free_term(ERL_CLOSURE_ELEMENT(ep,i),
+ INTERNAL, compound);
+ }
+ }
+ break;
+ } /* switch */
+
+ /* Clear header info for those cases where we are done */
+ ERL_TYPE(ep) = ERL_UNDEF;
+ erl_eterm_free(ep);
+ } else if (external) {
+ ERL_COUNT(ep)--;
+ external = INTERNAL;
+ goto restart;
+ }
+} /* _erl_free_term */
+#undef RESTART
+#undef FREE_AND_CLEAR
+
+void erl_free_array(ETERM **arr, int size)
+{
+ int i;
+
+ for (i=0; i<size; i++)
+ erl_free_term(arr[i]);
+
+} /* erl_free_array */
+
+
+void* erl_malloc (long size)
+{
+ void *res;
+
+ if ((res = ei_malloc(size)) == NULL)
+ erl_err_sys("<ERROR> erl_malloc: Failed to allocate more memory");
+
+ return res;
+}
+
+void* erl_realloc(void* orig, long size)
+{
+ void *res;
+
+ if ((res = ei_realloc(orig, size)) == NULL)
+ erl_err_sys("<ERROR> erl_realloc: Failed to allocate more memory");
+ return res;
+}
+
+void erl_free (void *ptr)
+{
+ ei_free(ptr);
+}
diff --git a/lib/erl_interface/src/legacy/erl_malloc.h b/lib/erl_interface/src/legacy/erl_malloc.h
new file mode 100644
index 0000000000..787d3bb98f
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_malloc.h
@@ -0,0 +1,26 @@
+/*
+ * %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%
+ */
+#ifndef _ERL_MALLOC_H
+#define _ERL_MALLOC_H
+
+/* FIXME: not documented */
+void *erl_realloc(void*, long);
+int erl_current_fix_desc(void);
+
+#endif /* _ERL_MALLOC_H */
diff --git a/lib/erl_interface/src/legacy/erl_marshal.c b/lib/erl_interface/src/legacy/erl_marshal.c
new file mode 100644
index 0000000000..4b5f28178f
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_marshal.c
@@ -0,0 +1,2117 @@
+/*
+ * %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%
+ */
+/*
+ * Purpose: Decoding and encoding Erlang terms.
+ */
+#include "eidef.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <string.h>
+
+#include "erl_interface.h"
+#include "erl_marshal.h"
+#include "erl_eterm.h"
+#include "erl_malloc.h"
+#include "erl_error.h"
+#include "erl_internal.h"
+
+#include "eiext.h" /* replaces external.h */
+#include "putget.h"
+
+static int is_string(ETERM* term);
+#if defined(VXWORKS) && CPU == PPC860
+int erl_fp_compare(unsigned *a, unsigned *b);
+static void erl_long_to_fp(long l, unsigned *d);
+#endif
+
+/* Used when comparing two encoded byte arrays */
+/* this global data is ok (from threading point of view) since it is
+ * initialized once and never changed
+ */
+
+#define CMP_ARRAY_SIZE 256
+/* FIXME problem for threaded ? */
+static char cmp_array[CMP_ARRAY_SIZE];
+static int init_cmp_array_p=1; /* initialize array, the first time */
+
+#if defined(VXWORKS) && CPU == PPC860
+#include <limits.h>
+#endif
+
+#if defined(__GNUC__)
+# define INLINE __inline__
+#elif defined(__WIN32__)
+# define INLINE __inline
+#else
+# define INLINE
+#endif
+
+static int cmp_floats(double f1, double f2);
+static INLINE double to_float(long l);
+
+#define ERL_NUM_CMP 1
+#define ERL_REF_CMP 3
+
+#define IS_ERL_NUM(t) (cmp_array[t]==ERL_NUM_CMP)
+
+#define CMP_NUM_CLASS_SIZE 256
+static unsigned char cmp_num_class[CMP_NUM_CLASS_SIZE];
+static int init_cmp_num_class_p=1; /* initialize array, the first time */
+
+#define MK_CMP_NUM_CODE(x,y) (((x)<<2)|(y))
+#define CMP_NUM_CLASS(x) (cmp_num_class[x] & 0x03)
+#define CMP_NUM_CODE(x,y) (MK_CMP_NUM_CODE(CMP_NUM_CLASS(x),CMP_NUM_CLASS(y)))
+
+#define SMALL 1
+#define FLOAT 2
+#define BIG 3
+
+#define SMALL_SMALL MK_CMP_NUM_CODE(SMALL,SMALL)
+#define SMALL_FLOAT MK_CMP_NUM_CODE(SMALL,FLOAT)
+#define SMALL_BIG MK_CMP_NUM_CODE(SMALL,BIG)
+#define FLOAT_SMALL MK_CMP_NUM_CODE(FLOAT,SMALL)
+#define FLOAT_FLOAT MK_CMP_NUM_CODE(FLOAT,FLOAT)
+#define FLOAT_BIG MK_CMP_NUM_CODE(FLOAT,BIG)
+#define BIG_SMALL MK_CMP_NUM_CODE(BIG,SMALL)
+#define BIG_FLOAT MK_CMP_NUM_CODE(BIG,FLOAT)
+#define BIG_BIG MK_CMP_NUM_CODE(BIG,BIG)
+
+void erl_init_marshal(void)
+{
+ if (init_cmp_array_p) {
+ memset(cmp_array, 0, CMP_ARRAY_SIZE);
+ cmp_array[ERL_SMALL_INTEGER_EXT] = 1;
+ cmp_array[ERL_INTEGER_EXT] = 1;
+ cmp_array[ERL_FLOAT_EXT] = 1;
+ cmp_array[ERL_SMALL_BIG_EXT] = 1;
+ cmp_array[ERL_LARGE_BIG_EXT] = 1;
+ cmp_array[ERL_ATOM_EXT] = 2;
+ cmp_array[ERL_REFERENCE_EXT] = 3;
+ cmp_array[ERL_NEW_REFERENCE_EXT] = 3;
+ cmp_array[ERL_FUN_EXT] = 4;
+ cmp_array[ERL_NEW_FUN_EXT] = 4;
+ cmp_array[ERL_PORT_EXT] = 5;
+ cmp_array[ERL_PID_EXT] = 6;
+ cmp_array[ERL_SMALL_TUPLE_EXT] = 7;
+ cmp_array[ERL_LARGE_TUPLE_EXT] = 7;
+ cmp_array[ERL_NIL_EXT] = 8;
+ cmp_array[ERL_STRING_EXT] = 9;
+ cmp_array[ERL_LIST_EXT] = 9;
+ cmp_array[ERL_BINARY_EXT] = 10;
+ init_cmp_array_p = 0;
+ }
+ if (init_cmp_num_class_p) {
+ memset(cmp_num_class, 0, CMP_NUM_CLASS_SIZE);
+ cmp_num_class[ERL_SMALL_INTEGER_EXT] = SMALL;
+ cmp_num_class[ERL_INTEGER_EXT] = SMALL;
+ cmp_num_class[ERL_FLOAT_EXT] = FLOAT;
+ cmp_num_class[ERL_SMALL_BIG_EXT] = BIG;
+ cmp_num_class[ERL_LARGE_BIG_EXT] = BIG;
+ init_cmp_num_class_p = 0;
+ }
+}
+
+/* The encoder calls length, if erl_length() should return */
+/* -1 for dotted pairs (why !!!!) we can't use erl_length() */
+/* from the encoder in erl_marshal.c */
+
+static int erl_length_x(const ETERM *ep) {
+ int n = 0;
+
+ if (!ep) return -1;
+
+ while (ERL_TYPE(ep) == ERL_LIST) {
+ n++;
+ ep = TAIL(ep);
+ }
+
+ return n;
+}
+
+
+/*==============================================================
+ * Marshalling routines.
+ *==============================================================
+ */
+
+/*
+ * The actual ENCODE engine.
+ * Returns 0 on success, otherwise 1.
+ */
+int erl_encode_it(ETERM *ep, unsigned char **ext, int dist)
+{
+ int i;
+ unsigned int u;
+ long long l;
+ unsigned long long ul;
+
+ switch(ERL_TYPE(ep))
+ {
+ case ERL_ATOM:
+ i = ep->uval.aval.len;
+ *(*ext)++ = ERL_ATOM_EXT;
+ *(*ext)++ = (i >>8) &0xff;
+ *(*ext)++ = i &0xff;
+ memcpy((void *) *ext, (const void *) ep->uval.aval.a, i);
+ *ext += i;
+ return 0;
+
+ case ERL_INTEGER:
+ i = ep->uval.ival.i;
+ /* ERL_SMALL_BIG */
+ if ((i > ERL_MAX) || (i < ERL_MIN)) {
+ *(*ext)++ = ERL_SMALL_BIG_EXT;
+ *(*ext)++ = 4; /* four bytes */
+ if ((*(*ext)++ = ((i>>31) & 0x01))) /* sign byte */
+ i = -i;
+ *(*ext)++ = i & 0xff; /* LSB first */
+ *(*ext)++ = (i >> 8) & 0xff;
+ *(*ext)++ = (i >> 16) & 0xff;
+ *(*ext)++ = (i >> 24) & 0x7f; /* Don't include the sign bit */
+ return 0;
+ }
+ /* SMALL_INTEGER */
+ if ((i < 256) && (i >= 0)) {
+ *(*ext)++ = ERL_SMALL_INTEGER_EXT;
+ *(*ext)++ = i & 0xff;
+ return 0;
+ }
+ /* INTEGER */
+ *(*ext)++ = ERL_INTEGER_EXT;
+ *(*ext)++ = (i >> 24) & 0xff;
+ *(*ext)++ = (i >> 16) & 0xff;
+ *(*ext)++ = (i >> 8) & 0xff;
+ *(*ext)++ = i & 0xff;
+ return 0;
+
+ case ERL_U_INTEGER:
+ u = ep->uval.uival.u;
+ /* ERL_U_SMALL_BIG */
+ if (u > ERL_MAX) {
+ *(*ext)++ = ERL_SMALL_BIG_EXT;
+ *(*ext)++ = 4; /* four bytes */
+ *(*ext)++ = 0; /* sign byte */
+ *(*ext)++ = u & 0xff; /* LSB first */
+ *(*ext)++ = (u >> 8) & 0xff;
+ *(*ext)++ = (u >> 16) & 0xff;
+ *(*ext)++ = (u >> 24) & 0xff;
+ return 0;
+ }
+ /* SMALL_INTEGER */
+ if ((u < 256) && (u >= 0)) {
+ *(*ext)++ = ERL_SMALL_INTEGER_EXT;
+ *(*ext)++ = u & 0xff;
+ return 0;
+ }
+ /* INTEGER */
+ *(*ext)++ = ERL_INTEGER_EXT;
+ *(*ext)++ = (u >> 24) & 0xff;
+ *(*ext)++ = (u >> 16) & 0xff;
+ *(*ext)++ = (u >> 8) & 0xff;
+ *(*ext)++ = u & 0xff;
+ return 0;
+ case ERL_LONGLONG:
+ l = ep->uval.llval.i;
+ /* ERL_SMALL_BIG */
+ if ((l > ((long long) ERL_MAX)) ||
+ (l < ((long long) ERL_MIN))) {
+ *(*ext)++ = ERL_SMALL_BIG_EXT;
+ *(*ext)++ = 8; /* eight bytes */
+ if ((*(*ext)++ = ((l>>63) & 0x01))) /* sign byte */
+ l = -l;
+ *(*ext)++ = l & 0xff; /* LSB first */
+ *(*ext)++ = (l >> 8) & 0xff;
+ *(*ext)++ = (l >> 16) & 0xff;
+ *(*ext)++ = (l >> 24) & 0xff;
+ *(*ext)++ = (l >> 32) & 0xff;
+ *(*ext)++ = (l >> 40) & 0xff;
+ *(*ext)++ = (l >> 48) & 0xff;
+ *(*ext)++ = (l >> 56) & 0x7f; /* Don't include the sign bit */
+ return 0;
+ }
+ /* SMALL_INTEGER */
+ if ((l < 256) && (l >= 0)) {
+ *(*ext)++ = ERL_SMALL_INTEGER_EXT;
+ *(*ext)++ = l & 0xff;
+ return 0;
+ }
+ /* INTEGER */
+ *(*ext)++ = ERL_INTEGER_EXT;
+ *(*ext)++ = (l >> 24) & 0xff;
+ *(*ext)++ = (l >> 16) & 0xff;
+ *(*ext)++ = (l >> 8) & 0xff;
+ *(*ext)++ = l & 0xff;
+ return 0;
+
+ case ERL_U_LONGLONG:
+ ul = ep->uval.ullval.u;
+ /* ERL_U_SMALL_BIG */
+ if (ul > ((unsigned long long) ERL_MAX)) {
+ *(*ext)++ = ERL_SMALL_BIG_EXT;
+ *(*ext)++ = 8; /* eight bytes */
+ *(*ext)++ = 0; /* sign byte */
+ *(*ext)++ = ul & 0xff; /* LSB first */
+ *(*ext)++ = (ul >> 8) & 0xff;
+ *(*ext)++ = (ul >> 16) & 0xff;
+ *(*ext)++ = (ul >> 24) & 0xff;
+ *(*ext)++ = (ul >> 32) & 0xff;
+ *(*ext)++ = (ul >> 40) & 0xff;
+ *(*ext)++ = (ul >> 48) & 0xff;
+ *(*ext)++ = (ul >> 56) & 0xff;
+ return 0;
+ }
+ /* SMALL_INTEGER */
+ if ((ul < 256) && (ul >= 0)) {
+ *(*ext)++ = ERL_SMALL_INTEGER_EXT;
+ *(*ext)++ = ul & 0xff;
+ return 0;
+ }
+ /* INTEGER */
+ *(*ext)++ = ERL_INTEGER_EXT;
+ *(*ext)++ = (ul >> 24) & 0xff;
+ *(*ext)++ = (ul >> 16) & 0xff;
+ *(*ext)++ = (ul >> 8) & 0xff;
+ *(*ext)++ = ul & 0xff;
+ return 0;
+
+ case ERL_PID:
+ *(*ext)++ = ERL_PID_EXT;
+ /* First poke in node as an atom */
+ i = strlen((char *)ERL_PID_NODE(ep));
+ *(*ext)++ = ERL_ATOM_EXT;
+ *(*ext)++ = (i >>8) &0xff;
+ *(*ext)++ = i &0xff;
+ memcpy(*ext, ERL_PID_NODE(ep), i);
+ *ext += i;
+ /* And then fill in the integer fields */
+ i = ERL_PID_NUMBER(ep);
+ *(*ext)++ = (i >> 24) &0xff;
+ *(*ext)++ = (i >> 16) &0xff;
+ *(*ext)++ = (i >> 8) &0xff;
+ *(*ext)++ = i &0xff;
+ i = ERL_PID_SERIAL(ep);
+ *(*ext)++ = (i >> 24) &0xff;
+ *(*ext)++ = (i >> 16) &0xff;
+ *(*ext)++ = (i >> 8) &0xff;
+ *(*ext)++ = i &0xff;
+ *(*ext)++ = ERL_PID_CREATION(ep);
+ return 0;
+ case ERL_REF: {
+ int len, j;
+
+ /* Always encode as an extended reference; all
+ participating parties are now expected to be
+ able to decode extended references. */
+
+ *(*ext)++ = ERL_NEW_REFERENCE_EXT;
+
+ i = strlen((char *)ERL_REF_NODE(ep));
+ len = ERL_REF_LEN(ep);
+ *(*ext)++ = (len >> 8) &0xff;
+ *(*ext)++ = len &0xff;
+
+ *(*ext)++ = ERL_ATOM_EXT;
+ *(*ext)++ = (i >> 8) &0xff;
+ *(*ext)++ = i &0xff;
+ memcpy(*ext, ERL_REF_NODE(ep), i);
+ *ext += i;
+ *(*ext)++ = ERL_REF_CREATION(ep);
+ /* Then the integer fields */
+ for (j = 0; j < ERL_REF_LEN(ep); j++) {
+ i = ERL_REF_NUMBERS(ep)[j];
+ *(*ext)++ = (i >> 24) &0xff;
+ *(*ext)++ = (i >> 16) &0xff;
+ *(*ext)++ = (i >> 8) &0xff;
+ *(*ext)++ = i &0xff;
+ }
+ }
+ return 0;
+ case ERL_PORT:
+ *(*ext)++ = ERL_PORT_EXT;
+ /* First poke in node as an atom */
+ i = strlen((char *)ERL_PORT_NODE(ep));
+ *(*ext)++ = ERL_ATOM_EXT;
+ *(*ext)++ = (i >>8) &0xff;
+ *(*ext)++ = i &0xff;
+ memcpy(*ext, ERL_PORT_NODE(ep), i);
+ *ext += i;
+ /* Then the integer fields */
+ i = ERL_PORT_NUMBER(ep);
+ *(*ext)++ = (i >> 24) &0xff;
+ *(*ext)++ = (i >> 16) &0xff;
+ *(*ext)++ = (i >> 8) &0xff;
+ *(*ext)++ = i &0xff;
+ *(*ext)++ = ERL_PORT_CREATION(ep);
+ return 0;
+ case ERL_EMPTY_LIST:
+ *(*ext)++ = ERL_NIL_EXT;
+ break;
+ case ERL_LIST:
+ i = is_string(ep);
+ if (0 < i && i < 0x10000) { /* String. */
+ *(*ext)++ = ERL_STRING_EXT;
+ *(*ext)++ = (i >>8) &0xff;
+ *(*ext)++ = i &0xff;
+ while (ERL_TYPE(ep) == ERL_LIST) {
+ *(*ext)++ = HEAD(ep)->uval.ival.i;
+ ep = TAIL(ep);
+ }
+ break;
+ } else { /* List. */
+ i = erl_length_x(ep);
+ *(*ext)++ = ERL_LIST_EXT;
+ *(*ext)++ = (i >> 24) &0xff;
+ *(*ext)++ = (i >> 16) &0xff;
+ *(*ext)++ = (i >> 8) &0xff;
+ *(*ext)++ = i &0xff;
+ while (ERL_TYPE(ep) == ERL_LIST) {
+ if (erl_encode_it(HEAD(ep), ext, dist))
+ return 1;
+ ep = TAIL(ep);
+ }
+ i = erl_encode_it(ep, ext, dist);
+ return i;
+ }
+ case ERL_TUPLE:
+ i = ep->uval.tval.size;
+ if (i <= 0xff) {
+ *(*ext)++ = ERL_SMALL_TUPLE_EXT;
+ *(*ext)++ = i & 0xff;
+ }
+ else {
+ *(*ext)++ = ERL_LARGE_TUPLE_EXT;
+ *(*ext)++ = (i >> 24) & 0xff;
+ *(*ext)++ = (i >> 16) & 0xff;
+ *(*ext)++ = (i >> 8) & 0xff;
+ *(*ext)++ = i & 0xff;
+ }
+ for (i=0; i<ep->uval.tval.size; i++)
+ if (erl_encode_it(ep->uval.tval.elems[i], ext, dist))
+ return 1;
+ break;
+ case ERL_FLOAT:
+ *(*ext)++ = ERL_FLOAT_EXT;
+ memset(*ext, 0, 31);
+ sprintf((char *) *ext, "%.20e", ep->uval.fval.f);
+ *ext += 31;
+ break;
+ case ERL_BINARY:
+ *(*ext)++ = ERL_BINARY_EXT;
+ i = ep->uval.bval.size;
+ *(*ext)++ = (i >> 24) & 0xff;
+ *(*ext)++ = (i >> 16) & 0xff;
+ *(*ext)++ = (i >> 8) & 0xff;
+ *(*ext)++ = i & 0xff;
+ memcpy((char *) *ext, (char*) ep->uval.bval.b, i);
+ *ext += i;
+ break;
+ case ERL_FUNCTION:
+ if (ERL_FUN_ARITY(ep) != -1) {
+ unsigned char *size_p = *ext + 1;
+ *(*ext)++ = ERL_NEW_FUN_EXT;
+ *ext += 4;
+ i = ERL_FUN_ARITY(ep);
+ put8(*ext, i);
+ memcpy(*ext, ERL_FUN_MD5(ep), 16);
+ *ext += 16;
+ i = ERL_FUN_NEW_INDEX(ep);
+ put32be(*ext, i);
+ i = ERL_CLOSURE_SIZE(ep);
+ put32be(*ext, i);
+ erl_encode_it(ERL_FUN_MODULE(ep), ext, dist);
+ erl_encode_it(ERL_FUN_INDEX(ep), ext, dist);
+ erl_encode_it(ERL_FUN_UNIQ(ep), ext, dist);
+ erl_encode_it(ERL_FUN_CREATOR(ep), ext, dist);
+ for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++)
+ erl_encode_it(ep->uval.funcval.closure[i], ext, dist);
+ if (size_p != NULL) {
+ i = *ext - size_p;
+ put32be(size_p, i);
+ }
+ } else {
+ *(*ext)++ = ERL_FUN_EXT;
+ i = ERL_CLOSURE_SIZE(ep);
+ *(*ext)++ = (i >> 24) & 0xff;
+ *(*ext)++ = (i >> 16) & 0xff;
+ *(*ext)++ = (i >> 8) & 0xff;
+ *(*ext)++ = i & 0xff;
+ erl_encode_it(ERL_FUN_CREATOR(ep), ext, dist);
+ erl_encode_it(ERL_FUN_MODULE(ep), ext, dist);
+ erl_encode_it(ERL_FUN_INDEX(ep), ext, dist);
+ erl_encode_it(ERL_FUN_UNIQ(ep), ext, dist);
+ for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++)
+ erl_encode_it(ep->uval.funcval.closure[i], ext, dist);
+ }
+ break;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * ENCODE an ETERM into a BUFFER, assuming BUFFER is of
+ * enough size. At success return number of bytes written
+ * into it, otherwise return 0.
+ */
+static int erl_encode3(ETERM *ep, unsigned char *t, int dist)
+{
+ unsigned char *x = t;
+
+ *x++ = ERL_VERSION_MAGIC;
+ if (erl_encode_it(ep, &x, dist)) {
+#ifdef DEBUG
+ erl_err_msg("<ERROR> erl_encode: Error while encoding");
+#endif
+ return 0;
+ }
+ return (x - t);
+
+}
+
+/* API */
+
+int erl_encode(ETERM *ep, unsigned char *t)
+{
+ return erl_encode3(ep, t, 4);
+}
+
+/* determine the buffer size that will be required for the eterm */
+static int erl_term_len_helper(ETERM *ep, int dist);
+
+/* FIXME hard coded dist version */
+int erl_term_len(ETERM *ep)
+{
+ return 1+erl_term_len_helper(ep, 4);
+}
+
+static int erl_term_len_helper(ETERM *ep, int dist)
+{
+ int len = 0;
+ int i;
+ unsigned int u;
+ long long l;
+ unsigned long long ul;
+
+ if (ep) {
+ switch (ERL_TYPE(ep)) {
+ case ERL_ATOM:
+ i = ep->uval.aval.len;
+ len = i + 3;
+ break;
+
+ case ERL_INTEGER:
+ i = ep->uval.ival.i;
+ if ((i > ERL_MAX) || (i < ERL_MIN)) len = 7;
+ else if ((i < 256) && (i >= 0)) len = 2;
+ else len = 5;
+ break;
+
+ case ERL_U_INTEGER:
+ u = ep->uval.uival.u;
+ if (u > ERL_MAX) len = 7;
+ else if (u < 256) len = 2;
+ else len = 5;
+ break;
+
+ case ERL_LONGLONG:
+ l = ep->uval.llval.i;
+ if ((l > ((long long) ERL_MAX)) ||
+ (l < ((long long) ERL_MIN))) len = 11;
+ else if ((l < 256) && (l >= 0)) len = 2;
+ else len = 5;
+ break;
+
+ case ERL_U_LONGLONG:
+ ul = ep->uval.ullval.u;
+ if (ul > ((unsigned long long) ERL_MAX)) len = 11;
+ else if (ul < 256) len = 2;
+ else len = 5;
+ break;
+
+ case ERL_PID:
+ /* 1 + N + 4 + 4 + 1 where N = 3 + strlen */
+ i = strlen((char *)ERL_PID_NODE(ep));
+ len = 13 + i;
+ break;
+
+ case ERL_REF:
+ i = strlen((char *)ERL_REF_NODE(ep));
+ if (dist >= 4 && ERL_REF_LEN(ep) > 1) {
+ len = 1 + 2 + (i+3) + 1 + ERL_REF_LEN(ep) * 4;
+ } else {
+ /* 1 + N + 4 + 1 where N = 3 + strlen */
+ len = 9 + i;
+ }
+ break;
+
+ case ERL_PORT:
+ /* 1 + N + 4 + 1 where N = 3 + strlen */
+ i = strlen((char *)ERL_PORT_NODE(ep));
+ len = 9 + i;
+ break;
+
+ case ERL_EMPTY_LIST:
+ len = 1;
+ break;
+
+ case ERL_LIST:
+ i = is_string(ep);
+ if ((i > 0) && (i < 0x10000)) { /* string: 3 + strlen */
+ for (len = 3; ERL_TYPE(ep) == ERL_LIST; ep = TAIL(ep)) {
+ len++;
+ }
+ }
+ else { /* list: 5 + len(elem1) + len(elem2) ... */
+ for (len = 5; ERL_TYPE(ep) == ERL_LIST; ep = TAIL(ep)) {
+ len += erl_term_len_helper(HEAD(ep), dist);
+ }
+ len += erl_term_len_helper(ep, dist); /* last element */
+ }
+ break;
+
+ case ERL_TUPLE:
+ /* (2 or 5) + len(elem1) + len(elem2) ... */
+ i = ep->uval.tval.size;
+ if (i <= 0xff) len = 2;
+ else len = 5;
+
+ for (i=0; i<ep->uval.tval.size; i++) {
+ len += erl_term_len_helper(ep->uval.tval.elems[i], dist);
+ }
+ break;
+
+ case ERL_FLOAT:
+ len = 32;
+ break;
+
+ case ERL_BINARY:
+ i = ep->uval.bval.size;
+ len = 5 + i;
+ break;
+
+ case ERL_FUNCTION:
+ if (ERL_FUN_ARITY(ep) == -1) {
+ len = 1 + 4;
+ len += erl_term_len_helper(ERL_FUN_CREATOR(ep),dist);
+ len += erl_term_len_helper(ERL_FUN_MODULE(ep),dist);
+ len += erl_term_len_helper(ERL_FUN_INDEX(ep),dist);
+ len += erl_term_len_helper(ERL_FUN_UNIQ(ep),dist);
+ for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++)
+ len += erl_term_len_helper(ERL_CLOSURE_ELEMENT(ep,i), dist);
+ } else {
+ len = 1 + 4 + 16 + 4 + 4;
+ len += erl_term_len_helper(ERL_FUN_MODULE(ep),dist);
+ len += erl_term_len_helper(ERL_FUN_INDEX(ep),dist);
+ len += erl_term_len_helper(ERL_FUN_UNIQ(ep),dist);
+ len += erl_term_len_helper(ERL_FUN_CREATOR(ep),dist);
+ for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++)
+ len += erl_term_len_helper(ERL_CLOSURE_ELEMENT(ep,i), dist);
+ }
+ break;
+
+ default:
+#ifdef DEBUG
+ fprintf(stderr, "Shouldn't happen: erl_term_len, unknown term type: '%c'\n",ERL_TYPE(ep));
+#endif
+ erl_errno = EINVAL;
+ exit(1);
+ }
+ }
+
+ return len;
+}
+
+/*
+ * This one makes it easy to ENCODE several CONSECUTIVE
+ * ETERM's into the same buffer.
+ */
+int erl_encode_buf(ETERM *ep, unsigned char **ext)
+{
+ unsigned char *start=*ext;
+
+ *(*ext)++ = ERL_VERSION_MAGIC;
+ if (erl_encode_it(ep, ext, 0)) {
+#ifdef DEBUG
+ erl_err_msg("<ERROR> erl_encode_buf: Error while encoding\n");
+#endif
+ return 0;
+ }
+ return (*ext - start);
+
+} /* erl_encode_buf */
+
+/*
+ * A nice macro to make it look cleaner in the
+ * cases of PID's,PORT's and REF's below.
+ * It reads the NODE name from a buffer.
+ */
+#define READ_THE_NODE(ext,cp,len,i) \
+/* eat first atom, repr. the node */ \
+if (**ext != ERL_ATOM_EXT) \
+ return (ETERM *) NULL; \
+*ext += 1; \
+i = (**ext << 8) | (*ext)[1]; \
+cp = (char *) *(ext) + 2; \
+*ext += (i + 2); \
+len = i
+
+#define STATIC_NODE_BUF_SZ 30
+
+#define SET_NODE(node,node_buf,cp,len) \
+if (len >= STATIC_NODE_BUF_SZ) node = malloc(len+1); \
+else node = node_buf; \
+memcpy(node, cp, len); \
+node[len] = '\0'
+
+#define RESET_NODE(node,len) \
+if (len >= STATIC_NODE_BUF_SZ) free(node)
+
+/*
+ * The actual DECODE engine.
+ * Returns NULL in case of failure.
+ */
+static ETERM *erl_decode_it(unsigned char **ext)
+{
+ char *cp;
+ ETERM *ep,*tp,*np;
+ unsigned int u,sign;
+ int i,j,len,arity;
+ double ff;
+
+ /* Assume we are going to decode an integer */
+ ep = erl_alloc_eterm(ERL_INTEGER);
+ ERL_COUNT(ep) = 1;
+
+ switch (*(*ext)++)
+ {
+ case ERL_INTEGER_EXT:
+ i = (int) (**ext << 24) | ((*ext)[1] << 16) |
+ ((*ext)[2] << 8) | (*ext)[3];
+ *ext += 4;
+ ep->uval.ival.i = i;
+ return ep;
+
+ case ERL_SMALL_INTEGER_EXT:
+ i = *(*ext)++;
+ ep->uval.ival.i = i;
+ return ep;
+
+ /* NOTE: The arity below for bigs is not really the arity (= number of digits) */
+ /* It is the byte count and this might cause problems in other parts... */
+ case ERL_SMALL_BIG_EXT:
+ arity = *(*ext)++;
+ goto big_cont;
+ case ERL_LARGE_BIG_EXT:
+ arity = (**ext << 24) | ((*ext)[1])<< 16 |
+ ((*ext)[2]) << 8 |((*ext)[3]);
+ *ext += 4;
+ big_cont:
+ sign = *(*ext)++;
+ if (arity > 8)
+ goto big_truncate;
+
+ if (arity == 8 && ((*ext)[7] & 0x80) && sign) {
+ /* MSB already occupied ! */
+ goto big_truncate;
+ }
+
+ if (arity == 4 && ((*ext)[3] & 0x80) && !sign) {
+ /* It will fit into an unsigned int !! */
+ u = (((*ext)[3] << 24)|((*ext)[2])<< 16|((*ext)[1]) << 8 |(**ext));
+ ERL_TYPE(ep) = ERL_U_INTEGER;
+ ep->uval.uival.u = u;
+ /* *ext += i; */
+ *ext += arity;
+ return ep;
+ } else if (arity == 4 && !((*ext)[3] & 0x80)) {
+ /* It will fit into an int !!
+ * Note: It comes in "one's-complement notation"
+ */
+ if (sign)
+ i = (int) (~(((*ext)[3] << 24) | ((*ext)[2])<< 16 |
+ ((*ext)[1]) << 8 | (**ext)) | (unsigned int) sign);
+ else
+ i = (int) (((*ext)[3] << 24) | ((*ext)[2])<< 16 |
+ ((*ext)[1]) << 8 | (**ext));
+ ERL_TYPE(ep) = ERL_INTEGER;
+ ep->uval.ival.i = i;
+ *ext += arity;
+ return ep;
+ } else if (arity == 8 && ((*ext)[7] & 0x80) && !sign) {
+ /* Fits in an unsigned long long */
+ int x;
+ unsigned long long ul = 0LL;
+
+ for(x = 0 ; x < arity ; x++) {
+ ul |= ((unsigned long long)(*ext)[x]) << ((unsigned long long)(8*x));
+ }
+
+ ERL_TYPE(ep) = ERL_U_LONGLONG;
+ ep->uval.ullval.u = ul;
+ *ext += arity;
+ return ep;
+ } else {
+ /* Fits in a long long */
+ int x;
+ long long l = 0LL;
+
+ for(x = 0 ; x < arity ; x++) {
+ l |= ((long long)(*ext)[x]) << ((long long)(8*x));
+ }
+
+ if (sign) l = (long long) (~l | (unsigned long long) sign);
+
+ ERL_TYPE(ep) = ERL_LONGLONG;
+ ep->uval.llval.i = l;
+ *ext += arity;
+ return ep;
+ }
+ big_truncate:
+ /* truncate to: (+/-) 1 */
+#ifdef DEBUG
+ erl_err_msg("<WARNING> erl_decode_it: Integer truncated...");
+#endif
+ ERL_TYPE(ep) = ERL_INTEGER;
+ ep->uval.ival.i = sign?-1:1;
+ *ext += arity;
+ return ep;
+
+ case ERL_ATOM_EXT:
+ ERL_TYPE(ep) = ERL_ATOM;
+ i = (**ext << 8) | (*ext)[1];
+ cp = (char *) *(ext) + 2;
+ *ext += (i + 2);
+ ep->uval.aval.len = i;
+ ep->uval.aval.a = (char *) erl_malloc(i+1);
+ memcpy(ep->uval.aval.a, cp, i);
+ ep->uval.aval.a[i]='\0';
+ return ep;
+
+ case ERL_PID_EXT:
+ erl_free_term(ep);
+ { /* Why not use the constructors? */
+ char *node;
+ char node_buf[STATIC_NODE_BUF_SZ];
+ unsigned int number, serial;
+ unsigned char creation;
+ ETERM *eterm_p;
+
+ READ_THE_NODE(ext,cp,len,i);
+ SET_NODE(node,node_buf,cp,len);
+
+ /* get the integers */
+#if 0
+ /* FIXME: Remove code or whatever....
+ Ints on the wire are big-endian (== network byte order)
+ so use ntoh[sl]. (But some are little-endian! Arrrgh!)
+ Also, the libc authors can be expected to optimize them
+ heavily. However, the marshalling makes no guarantees
+ about alignments -- so it won't work at all. */
+ number = ntohl(*((unsigned int *)*ext)++);
+ serial = ntohl(*((unsigned int *)*ext)++);
+#else
+ number = ((*ext)[0] << 24) | ((*ext)[1]) << 16 |
+ ((*ext)[2]) << 8 | ((*ext)[3]);
+ *ext += 4;
+ serial = ((*ext)[0] << 24) | ((*ext)[1]) << 16 |
+ ((*ext)[2]) << 8 | ((*ext)[3]);
+ *ext += 4;
+#endif
+ creation = *(*ext)++;
+ eterm_p = erl_mk_pid(node, number, serial, creation);
+ RESET_NODE(node,len);
+ return eterm_p;
+ }
+ case ERL_REFERENCE_EXT:
+ erl_free_term(ep);
+ {
+ char *node;
+ char node_buf[STATIC_NODE_BUF_SZ];
+ unsigned int number;
+ unsigned char creation;
+ ETERM *eterm_p;
+
+ READ_THE_NODE(ext,cp,len,i);
+ SET_NODE(node,node_buf,cp,len);
+
+ /* get the integers */
+#if 0
+ number = ntohl(*((unsigned int *)*ext)++);
+#else
+ number = ((*ext)[0] << 24) | ((*ext)[1]) << 16 |
+ ((*ext)[2]) << 8 | ((*ext)[3]);
+ *ext += 4;
+#endif
+ creation = *(*ext)++;
+ eterm_p = erl_mk_ref(node, number, creation);
+ RESET_NODE(node,len);
+ return eterm_p;
+ }
+
+ case ERL_NEW_REFERENCE_EXT:
+ erl_free_term(ep);
+ {
+ char *node;
+ char node_buf[STATIC_NODE_BUF_SZ];
+ size_t cnt, i;
+ unsigned int n[3];
+ unsigned char creation;
+ ETERM *eterm_p;
+
+#if 0
+ cnt = ntohs(*((unsigned short *)*ext)++);
+#else
+ cnt = ((*ext)[0] << 8) | (*ext)[1];
+ *ext += 2;
+#endif
+
+ READ_THE_NODE(ext,cp,len,i);
+ SET_NODE(node,node_buf,cp,len);
+
+ /* get the integers */
+ creation = *(*ext)++;
+ for(i = 0; i < cnt; i++)
+ {
+#if 0
+ n[i] = ntohl(*((unsigned int *)*ext)++);
+#else
+ n[i] = ((*ext)[0] << 24) | ((*ext)[1]) << 16 |
+ ((*ext)[2]) << 8 | ((*ext)[3]);
+ *ext += 4;
+#endif
+ }
+ eterm_p = __erl_mk_reference(node, cnt, n, creation);
+ RESET_NODE(node,len);
+ return eterm_p;
+ }
+
+ case ERL_PORT_EXT:
+ erl_free_term(ep);
+ {
+ char *node;
+ char node_buf[STATIC_NODE_BUF_SZ];
+ unsigned int number;
+ unsigned char creation;
+ ETERM *eterm_p;
+
+ READ_THE_NODE(ext,cp,len,i);
+ SET_NODE(node,node_buf,cp,len);
+
+ /* get the integers */
+#if 0
+ number = ntohl(*((unsigned int *)*ext)++);
+#else
+ number = ((*ext)[0] << 24) | ((*ext)[1]) << 16 |
+ ((*ext)[2]) << 8 | ((*ext)[3]);
+ *ext += 4;
+#endif
+ creation = *(*ext)++;
+ eterm_p = erl_mk_port(node, number, creation);
+ RESET_NODE(node,len);
+ return eterm_p;
+ }
+
+ case ERL_NIL_EXT:
+ ERL_TYPE(ep) = ERL_EMPTY_LIST;
+ return ep;
+
+ case ERL_LIST_EXT:
+ ERL_TYPE(ep) = ERL_LIST;
+ i = (**ext << 24) | ((*ext)[1] << 16) |((*ext)[2] << 8) | (*ext)[3];
+ *ext += 4;
+ /* ASSERT(i != 0); */ /* Should be represented by ERL_NIL_EXT. */
+ tp = ep;
+ for (j = 0; j < i; j++)
+ if ((HEAD(tp) = erl_decode_it(ext)) == NULL)
+ goto failure;
+ else if (j + 1 < i) {
+ /* We have to watch out for how we allocates the
+ * last tail element since we may encounter non-
+ * well formed lists.
+ */
+ np = erl_alloc_eterm(ERL_LIST);
+ ERL_COUNT(np) = 1;
+ TAIL(np) = NULL; /* in case of failure */
+ TAIL(tp) = np;
+ tp = np;
+ }
+ if ((TAIL(tp) = erl_decode_it(ext)) == NULL)
+ goto failure;
+ return ep;
+
+ case ERL_STRING_EXT:
+ {
+ unsigned char* s;
+
+ ERL_TYPE(ep) = ERL_EMPTY_LIST;
+ i = (**ext << 8) | ((*ext)[1]);
+ *ext += 2;
+ s = *ext+i;
+
+ while (*ext < s) {
+ ETERM* integer;
+ ETERM* cons;
+
+ integer = erl_alloc_eterm(ERL_INTEGER);
+ ERL_COUNT(integer) = 1;
+ integer->uval.ival.i = *--s;
+
+ cons = erl_alloc_eterm(ERL_LIST);
+ ERL_COUNT(cons) = 1;
+ HEAD(cons) = integer;
+ TAIL(cons) = ep;
+ ep = cons;
+ }
+ *ext += i;
+ return ep;
+ }
+
+ case ERL_SMALL_TUPLE_EXT:
+ ERL_TYPE(ep) = ERL_TUPLE;
+ i = *(*ext)++;
+ goto decode_tuple;
+
+ case ERL_LARGE_TUPLE_EXT:
+ i = (**ext << 24) | ((*ext)[1]) << 16 |
+ ((*ext)[2]) << 8 | ((*ext)[3]) ;
+ *ext += 4;
+ decode_tuple:
+ ep->uval.tval.size = i;
+ j = (i + 1) * sizeof(ETERM*);
+ ep->uval.tval.elems = (ETERM**) erl_malloc(j);
+ memset(ep->uval.tval.elems, 0, j); /* in case of failure below... */
+ for (i=0; i<ep->uval.tval.size; i++)
+ if ((tp = erl_decode_it(ext)) == NULL)
+ goto failure;
+ else
+ ep->uval.tval.elems[i] = tp;
+ return ep;
+
+ case ERL_FLOAT_EXT:
+ ERL_TYPE(ep) = ERL_FLOAT;
+ if (sscanf((char *) *ext, "%lf", &ff) != 1)
+ goto failure;
+ *ext += 31;
+ ep->uval.fval.f = ff;
+ return ep;
+
+ case ERL_BINARY_EXT:
+ ERL_TYPE(ep) = ERL_BINARY;
+ i = (**ext << 24) | ((*ext)[1] << 16) |
+ ((*ext)[2] << 8) | (*ext)[3];
+ *ext += 4;
+ ep->uval.bval.size = i;
+ ep->uval.bval.b = (unsigned char *) erl_malloc(i);
+ memcpy(ep->uval.bval.b, *ext, i);
+ *ext += i;
+ return ep;
+
+ case ERL_FUN_EXT: /* FIXME: error checking */
+ ERL_TYPE(ep) = ERL_FUNCTION;
+ i = get32be(*ext);
+ /*i = *(**ext << 24) | ((*ext)[1] << 16) | ((*ext)[2] << 8) | (*ext)[3];
+ *ext += 4; */
+ ERL_FUN_ARITY(ep) = -1;
+ ERL_CLOSURE_SIZE(ep) = i;
+ ERL_FUN_CREATOR(ep) = erl_decode_it(ext);
+ ERL_FUN_MODULE(ep) = erl_decode_it(ext);
+ ERL_FUN_INDEX(ep) = erl_decode_it(ext);
+ ERL_FUN_UNIQ(ep) = erl_decode_it(ext);
+ j = i * sizeof(ETERM*);
+ ERL_CLOSURE(ep) = (ETERM**) erl_malloc(j);
+ memset(ERL_CLOSURE(ep), 0, j);
+ for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++)
+ ERL_CLOSURE_ELEMENT(ep,i) = erl_decode_it(ext);
+ return ep;
+
+ case ERL_NEW_FUN_EXT: /* FIXME: error checking */
+ ERL_TYPE(ep) = ERL_FUNCTION;
+ i = get32be(*ext); /* size, we don't use it here */
+ ERL_FUN_ARITY(ep) = get8(*ext);
+ memcpy(ERL_FUN_MD5(ep), *ext, 16);
+ *ext += 16;
+ ERL_FUN_NEW_INDEX(ep) = get32be(*ext);
+ i = get32be(*ext);
+ ERL_CLOSURE_SIZE(ep) = i;
+ ERL_FUN_MODULE(ep) = erl_decode_it(ext);
+ ERL_FUN_INDEX(ep) = erl_decode_it(ext);
+ ERL_FUN_UNIQ(ep) = erl_decode_it(ext);
+ ERL_FUN_CREATOR(ep) = erl_decode_it(ext);
+ j = i * sizeof(ETERM*);
+ ERL_CLOSURE(ep) = (ETERM**) erl_malloc(j);
+ memset(ERL_CLOSURE(ep), 0, j);
+ for (i = 0; i < ERL_CLOSURE_SIZE(ep); i++)
+ ERL_CLOSURE_ELEMENT(ep,i) = erl_decode_it(ext);
+ return ep;
+
+ } /* switch */
+
+ failure:
+ erl_free_term(ep);
+ return (ETERM *) NULL;
+
+} /* erl_decode_it */
+
+/*
+ * DECODE a buffer of BYTES into an ETERM.
+ * Returns NULL in case of failure.
+ */
+ETERM *erl_decode(unsigned char *t)
+{
+ ETERM *ep;
+ unsigned char *ext;
+
+ ext = t;
+
+ /* We ignore the version magic since it might be
+ * possible that the buffer has been manipulated
+ * with erl_peek_ext.
+ */
+ if (*ext == ERL_VERSION_MAGIC)
+ ext++;
+
+ ep = NULL;
+ ep = erl_decode_it(&ext);
+#ifdef DEBUG
+ if (!ep) erl_err_msg("<ERROR> erl_decode: Error while decoding");
+#endif
+ return ep;
+
+} /* erl_decode */
+
+/*
+ * This one makes it possible to DECODE two CONSECUTIVE
+ * ETERM's in the same buffer.
+ */
+ETERM *erl_decode_buf(unsigned char **ext)
+{
+ ETERM *ep;
+
+ /* We ignore the version magic since it might be
+ * possible that the buffer has been manipulated
+ * with erl_peek_ext.
+ */
+ if (**ext == ERL_VERSION_MAGIC)
+ (*ext)++;
+
+ ep = NULL;
+ ep = erl_decode_it(ext);
+#ifdef DEBUG
+ if (!ep) erl_err_msg("<ERROR> erl_decode_buf: Error while decoding");
+#endif
+ return ep;
+
+} /* erl_decode_buf */
+
+
+/*==============================================================
+ * Ok, here comes routines for inspecting/manipulating
+ * an encoded buffer of bytes.
+ *==============================================================
+ */
+
+/*
+ * Return 1 if the VERSION MAGIC in the BUFFER is the
+ * same as the this library version.
+ */
+int erl_verify_magic(unsigned char *ext)
+{
+
+ if (*ext == ERL_VERSION_MAGIC)
+ return 1;
+ else
+ return 0;
+
+} /* erl_verify_magic */
+
+/*
+ * Return the TYPE of an ENCODED ETERM.
+ * At failure, return 0.
+ */
+unsigned char erl_ext_type(unsigned char *ext)
+{
+ /* FIXME old code could skip multiple magic */
+
+ /* Move over magic number if any */
+ if (*ext == ERL_VERSION_MAGIC) ext++;
+
+ switch (*ext) {
+ case ERL_SMALL_INTEGER_EXT:
+ case ERL_INTEGER_EXT:
+ return ERL_INTEGER;
+ case ERL_ATOM_EXT:
+ return ERL_ATOM;
+ case ERL_PID_EXT:
+ return ERL_PID;
+ case ERL_PORT_EXT:
+ return ERL_PORT;
+ case ERL_REFERENCE_EXT:
+ case ERL_NEW_REFERENCE_EXT:
+ return ERL_REF;
+ case ERL_NIL_EXT:
+ return ERL_EMPTY_LIST;
+ case ERL_LIST_EXT:
+ return ERL_LIST;
+ case ERL_SMALL_TUPLE_EXT:
+ case ERL_LARGE_TUPLE_EXT:
+ return ERL_TUPLE;
+ case ERL_FLOAT_EXT:
+ return ERL_FLOAT;
+ case ERL_BINARY_EXT:
+ return ERL_BINARY;
+ case ERL_FUN_EXT:
+ case ERL_NEW_FUN_EXT:
+ return ERL_FUNCTION;
+ case ERL_SMALL_BIG_EXT:
+ case ERL_LARGE_BIG_EXT:
+ return ERL_BIG;
+ default:
+ return 0;
+
+ } /* switch */
+
+} /* erl_ext_type */
+
+/*
+ * Returns the number of elements in compund
+ * terms. For other kind of terms zero is returned.
+ * At failure -1 is returned.
+ */
+int erl_ext_size(unsigned char *t)
+{
+ int i;
+ unsigned char *v;
+
+ if (*t == ERL_VERSION_MAGIC)
+ return erl_ext_size(t+1);
+
+ v = t+1;
+ switch(*t) {
+ case ERL_SMALL_INTEGER_EXT:
+ case ERL_INTEGER_EXT:
+ case ERL_ATOM_EXT:
+ case ERL_PID_EXT:
+ case ERL_PORT_EXT:
+ case ERL_REFERENCE_EXT:
+ case ERL_NEW_REFERENCE_EXT:
+ case ERL_NIL_EXT:
+ case ERL_BINARY_EXT:
+ case ERL_STRING_EXT:
+ case ERL_FLOAT_EXT:
+ case ERL_SMALL_BIG_EXT:
+ case ERL_LARGE_BIG_EXT:
+ return 0;
+ break;
+ case ERL_SMALL_TUPLE_EXT:
+ i = v[0];
+ return i;
+ break;
+ case ERL_LIST_EXT:
+ case ERL_LARGE_TUPLE_EXT:
+ i = (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3];
+ return i;
+ break;
+ case ERL_FUN_EXT:
+ i = (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3];
+ return i+4;
+ break;
+ case ERL_NEW_FUN_EXT:
+ v += 4 + 1 + 16 + 4;
+ i = get32be(v);
+ return i + 4;
+ break;
+ default:
+ return -1;
+ break;
+ } /* switch */
+
+} /* ext_size */
+
+/*
+ * A nice macro that eats up the atom pointed to.
+ */
+#define JUMP_ATOM(ext,i) \
+if (**ext != ERL_ATOM_EXT) \
+ return 0; \
+*ext += 1; \
+i = (**ext << 8) | (*ext)[1]; \
+*ext += (i + 2)
+
+/*
+ * MOVE the POINTER PAST the ENCODED ETERM we
+ * are currently pointing at. Returns 1 at
+ * success, otherwise 0.
+ */
+static int jump(unsigned char **ext)
+{
+ int j,k,i=0;
+ int n;
+
+ switch (*(*ext)++) {
+ case ERL_VERSION_MAGIC:
+ return jump(ext);
+ case ERL_INTEGER_EXT:
+ *ext += 4;
+ break;
+ case ERL_SMALL_INTEGER_EXT:
+ *ext += 1;
+ break;
+ case ERL_ATOM_EXT:
+ i = (**ext << 8) | (*ext)[1];
+ *ext += (i + 2);
+ break;
+ case ERL_PID_EXT:
+ /* eat first atom */
+ JUMP_ATOM(ext,i);
+ *ext += 9; /* Two int's and the creation field */
+ break;
+ case ERL_REFERENCE_EXT:
+ case ERL_PORT_EXT:
+ /* first field is an atom */
+ JUMP_ATOM(ext,i);
+ *ext += 5; /* One int and the creation field */
+ break;
+ case ERL_NEW_REFERENCE_EXT:
+ n = (**ext << 8) | (*ext)[1];
+ *ext += 2;
+ /* first field is an atom */
+ JUMP_ATOM(ext,i);
+ *ext += 4*n+1;
+ break;
+ case ERL_NIL_EXT:
+ /* We just passed it... */
+ break;
+ case ERL_LIST_EXT:
+ i = j = 0;
+ j = (**ext << 24) | ((*ext)[1] << 16) |((*ext)[2] << 8) | (*ext)[3];
+ *ext += 4;
+ for(k=0; k<j; k++)
+ if ((i = jump(ext)) == 0)
+ return(0);
+ if (**ext == ERL_NIL_EXT) {
+ *ext += 1;
+ break;
+ }
+ if (jump(ext) == 0) return 0;
+ break;
+ case ERL_STRING_EXT:
+ i = **ext << 8 | (*ext)[1];
+ *ext += 2 + i;
+ break;
+ case ERL_SMALL_TUPLE_EXT:
+ i = *(*ext)++;
+ goto jump_tuple;
+ case ERL_LARGE_TUPLE_EXT:
+ i = (**ext << 24) | ((*ext)[1] << 16) |((*ext)[2] << 8) | (*ext)[3];
+ *ext += 4;
+ jump_tuple:
+ for (j = 0; j < i; j++)
+ if ((k = jump(ext)) == 0)
+ return(0);
+ break;
+ case ERL_FLOAT_EXT:
+ *ext += 31;
+ break;
+ case ERL_BINARY_EXT:
+ i = (**ext << 24) | ((*ext)[1] << 16) |((*ext)[2] << 8) | (*ext)[3];
+ *ext += 4+i;
+ break;
+ case ERL_FUN_EXT:
+ i = (**ext << 24) | ((*ext)[1] << 16) |((*ext)[2] << 8) | (*ext)[3];
+ *ext += 4;
+ i += 4;
+ for (j = 0; j < i; j++)
+ if ((k = jump(ext)) == 0)
+ return(0);
+ break;
+ case ERL_NEW_FUN_EXT:
+ i = get32be(*ext);
+ *ext += i + 4;
+ break;
+ case ERL_SMALL_BIG_EXT:
+ i = *(*ext);
+ *ext += i + 1;
+ break;
+ case ERL_LARGE_BIG_EXT:
+ i = get32be(*ext);
+ *ext += i + 4;
+ break;
+ default:
+ return 0;
+ } /* switch */
+
+ return 1;
+
+} /* jump */
+
+/*
+ * The actual PEEK engine.
+ */
+static unsigned char *peek_ext(unsigned char **ext, int jumps)
+{
+ int i;
+
+ switch (*(*ext)++)
+ {
+ case ERL_VERSION_MAGIC:
+ return peek_ext(ext, jumps);
+ case ERL_SMALL_TUPLE_EXT:
+ i = *(*ext)++;
+ goto do_the_peek_stuff;
+ case ERL_LARGE_TUPLE_EXT:
+ case ERL_LIST_EXT:
+ i = (**ext << 24) | ((*ext)[1]) << 16| ((*ext)[2]) << 8| ((*ext)[3]) ;
+ *ext += 4;
+ do_the_peek_stuff:
+ if (i <= jumps) {
+#ifdef DEBUG
+ erl_err_msg("<ERROR> peek_ext: Out of range");
+#endif
+ return NULL;
+ }
+ for(i=0; i<jumps; i++)
+ if (!jump(ext)) {
+#ifdef DEBUG
+ erl_err_msg("<ERROR> peek_ext: Bad data");
+#endif
+ return NULL;
+ }
+ return *ext;
+ default:
+#ifdef DEBUG
+ erl_err_msg("<ERROR> peek_ext: Can't peek in non list/tuple type");
+#endif
+ return NULL;
+ } /* switch */
+
+} /* peek_ext */
+
+/*
+ * Return a POINTER TO the N:TH ELEMENT in a
+ * COMPUND ENCODED ETERM.
+ */
+unsigned char *erl_peek_ext(unsigned char *ext, int jumps)
+{
+ unsigned char *x=ext;
+
+ return peek_ext(&x, jumps);
+
+} /* erl_peek_ext */
+
+/*
+ * Lexically compare two strings of bytes,
+ * (string s1 length l1 and s2 l2).
+ * Return: -1 if s1 < s2
+ * 0 if s1 = s2
+ * 1 if s1 > s2
+ */
+static int cmpbytes(unsigned char* s1,int l1,unsigned char* s2,int l2)
+{
+ int i;
+ i = 0;
+ while((i < l1) && (i < l2)) {
+ if (s1[i] < s2[i]) return(-1);
+ if (s1[i] > s2[i]) return(1);
+ i++;
+ }
+ if (l1 < l2) return(-1);
+ if (l1 > l2) return(1);
+ return(0);
+
+} /* cmpbytes */
+
+#define CMP_EXT_ERROR_CODE 4711
+
+#define CMP_EXT_INT32_BE(AP, BP) \
+do { \
+ if ((AP)[0] != (BP)[0]) return (AP)[0] < (BP)[0] ? -1 : 1; \
+ if ((AP)[1] != (BP)[1]) return (AP)[1] < (BP)[1] ? -1 : 1; \
+ if ((AP)[2] != (BP)[2]) return (AP)[2] < (BP)[2] ? -1 : 1; \
+ if ((AP)[3] != (BP)[3]) return (AP)[3] < (BP)[3] ? -1 : 1; \
+} while (0)
+
+#define CMP_EXT_SKIP_ATOM(EP) \
+do { \
+ if ((EP)[0] != ERL_ATOM_EXT) \
+ return CMP_EXT_ERROR_CODE; \
+ (EP) += 3 + ((EP)[1] << 8 | (EP)[2]); \
+} while (0)
+
+/*
+ * We now know that both byte arrays are of the same type.
+ */
+static int compare_top_ext(unsigned char**, unsigned char **); /* forward */
+static int cmp_exe2(unsigned char **e1, unsigned char **e2);
+
+static int cmp_refs(unsigned char **e1, unsigned char **e2)
+{
+ int tmp, n1, n2;
+ unsigned char *node1, *node2, *id1, *id2, cre1, cre2;
+
+ if (*((*e1)++) == ERL_REFERENCE_EXT) {
+ node1 = *e1;
+ CMP_EXT_SKIP_ATOM(*e1);
+ n1 = 1;
+ id1 = *e1;
+ cre1 = (*e1)[4];
+ *e1 += 5;
+ } else {
+ n1 = get16be(*e1);
+ node1 = *e1;
+ CMP_EXT_SKIP_ATOM(*e1);
+ cre1 = **e1;
+ id1 = (*e1) + 1 + (n1 - 1)*4;
+ *e1 = id1 + 4;
+ }
+
+ if (*((*e2)++) == ERL_REFERENCE_EXT) {
+ node2 = *e2;
+ CMP_EXT_SKIP_ATOM(*e2);
+ n2 = 1;
+ id2 = *e2;
+ cre2 = (*e2)[4];
+ *e2 += 5;
+ } else {
+ n2 = get16be(*e2);
+ node2 = *e2;
+ CMP_EXT_SKIP_ATOM(*e2);
+ cre2 = **e2;
+ id2 = (*e2) + 1 + (n2 - 1)*4;
+ *e2 = id2 + 4;
+ }
+
+ /* First compare node names... */
+ tmp = cmp_exe2(&node1, &node2);
+ if (tmp != 0)
+ return tmp;
+
+ /* ... then creations ... */
+ if (cre1 != cre2)
+ return cre1 < cre2 ? -1 : 1;
+
+ /* ... and then finaly ids. */
+ if (n1 != n2) {
+ unsigned char zero[] = {0, 0, 0, 0};
+ if (n1 > n2)
+ do {
+ CMP_EXT_INT32_BE(id1, zero);
+ id1 -= 4;
+ n1--;
+ } while (n1 > n2);
+ else
+ do {
+ CMP_EXT_INT32_BE(zero, id2);
+ id2 -= 4;
+ n2--;
+ } while (n2 > n1);
+ }
+
+ for (; n1 > 0; n1--, id1 -= 4, id2 -= 4)
+ CMP_EXT_INT32_BE(id1, id2);
+
+ return 0;
+}
+
+static int cmp_string_list(unsigned char **e1, unsigned char **e2) {
+
+ /* we need to compare a string in **e1 and a list in **e2 */
+ /* convert the string to list representation and convert that with e2 */
+ /* we need a temporary buffer of: */
+ /* 5 (list tag + length) + 2*string length + 1 (end of list tag) */
+ /* for short lists we use a stack allocated buffer, otherwise we malloc */
+
+ unsigned char *bp;
+ unsigned char buf[5+2*255+1]; /* used for short lists */
+ int i,e1_len;
+ int res;
+
+ e1_len = ((*e1)[1] << 8) | ((*e1)[2]);
+ if ( e1_len < 256 ) {
+ bp = buf;
+ } else {
+ bp = malloc(5+(2*e1_len)+1);
+ }
+
+ bp[0] = ERL_LIST_EXT;
+ bp[1] = bp[2] = 0;
+ bp[3] = (*e1)[1];
+ bp[4] = (*e1)[2];
+
+ for(i=0;i<e1_len;i++) {
+ bp[5+2*i] = ERL_SMALL_INTEGER_EXT;
+ bp[5+2*i+1] = (*e1)[3+i];
+ }
+
+ bp[5+2*e1_len] = ERL_NIL_EXT;
+
+ res = cmp_exe2(&bp, e2);
+
+ if ( e1_len >= 256 ) free(bp);
+
+ return res;
+}
+
+static int cmp_exe2(unsigned char **e1, unsigned char **e2)
+{
+ int min, ret,i,j,k;
+ double ff1, ff2;
+ unsigned char *tmp1, *tmp2;
+
+ if ( ((*e1)[0] == ERL_STRING_EXT) && ((*e2)[0] == ERL_LIST_EXT) ) {
+ return cmp_string_list(e1, e2);
+ } else if ( ((*e1)[0] == ERL_LIST_EXT) && ((*e2)[0] == ERL_STRING_EXT) ) {
+ return -cmp_string_list(e2, e1);
+ }
+
+ *e2 += 1;
+ switch (*(*e1)++)
+ {
+ case ERL_SMALL_INTEGER_EXT:
+ if (**e1 < **e2) ret = -1;
+ else if (**e1 > **e2) ret = 1;
+ else ret = 0;
+ *e1 += 1; *e2 += 1;
+ return ret;
+ case ERL_INTEGER_EXT:
+ i = (int) (**e1 << 24) | ((*e1)[1] << 16) |((*e1)[2] << 8) | (*e1)[3];
+ j = (int) (**e2 << 24) | ((*e2)[1] << 16) |((*e2)[2] << 8) | (*e2)[3];
+ if ( i < j)
+ ret = -1;
+ else if ( i > j)
+ ret = 1;
+ else
+ ret = 0;
+ *e1 += 4; *e2 += 4;
+ return ret;
+ case ERL_ATOM_EXT:
+ i = (**e1 << 8) | (*e1)[1];
+ j = (**e2 << 8) | (*e2)[1];
+ ret = cmpbytes(*e1 +2, i, *e2 +2, j);
+ *e1 += (i + 2);
+ *e2 += (j + 2);
+ return ret;
+ case ERL_PID_EXT: {
+ unsigned char *n1 = *e1;
+ unsigned char *n2 = *e2;
+ CMP_EXT_SKIP_ATOM(*e1); CMP_EXT_SKIP_ATOM(*e2);
+ *e1 += 9; *e2 += 9;
+
+ /* First compare serials ... */
+ tmp1 = *e1 - 5; tmp2 = *e2 - 5;
+ CMP_EXT_INT32_BE(tmp1, tmp2);
+
+ /* ... then ids ... */
+ tmp1 -= 4; tmp2 -= 4;
+ CMP_EXT_INT32_BE(tmp1, tmp2);
+
+ /* ... then node names ... */
+ ret = cmp_exe2(&n1, &n2);
+ if (ret != 0)
+ return ret;
+
+ /* ... and then finaly creations. */
+ tmp1 += 8; tmp2 += 8;
+ if (*tmp1 != *tmp2)
+ return *tmp1 < *tmp2 ? -1 : 1;
+ return 0;
+ }
+ case ERL_PORT_EXT:
+ /* First compare node names ... */
+ if (**e1 != ERL_ATOM_EXT || **e2 != ERL_ATOM_EXT)
+ return CMP_EXT_ERROR_CODE;
+ ret = cmp_exe2(e1, e2);
+ *e1 += 5; *e2 += 5;
+ if (ret != 0)
+ return ret;
+ /* ... then creations ... */
+ tmp1 = *e1 - 1; tmp2 = *e2 - 1;
+ if (*tmp1 != *tmp2)
+ return *tmp1 < *tmp2 ? -1 : 1;
+ /* ... and then finaly ids. */
+ tmp1 -= 4; tmp2 -= 4;
+ CMP_EXT_INT32_BE(tmp1, tmp2);
+ return 0;
+ case ERL_NIL_EXT: return 0;
+ case ERL_LIST_EXT:
+ i = (**e1 << 24) | ((*e1)[1] << 16) |((*e1)[2] << 8) | (*e1)[3];
+ *e1 += 4;
+ j = (**e2 << 24) | ((*e2)[1] << 16) |((*e2)[2] << 8) | (*e2)[3];
+ *e2 += 4;
+ if ( i == j && j == 0 ) return 0;
+ min = (i < j) ? i : j;
+ k = 0;
+ while (1) {
+ if (k++ == min)
+ return compare_top_ext(e1 , e2);
+ if ((ret = compare_top_ext(e1 , e2)) == 0)
+ continue;
+ return ret;
+ }
+ case ERL_STRING_EXT:
+ i = (**e1 << 8) | ((*e1)[1]);
+ *e1 += 2;
+ j = (**e2 << 8) | ((*e2)[1]);
+ *e2 += 2;
+ ret = cmpbytes(*e1, i, *e2, j);
+ *e1 += i;
+ *e2 += j;
+ return ret;
+ case ERL_SMALL_TUPLE_EXT:
+ i = *(*e1)++; j = *(*e2)++;
+ if (i < j) return -1;
+ if (i > j ) return 1;
+ while (i--) {
+ if ((j = compare_top_ext(e1, e2))) return j;
+ }
+ return 0;
+ case ERL_LARGE_TUPLE_EXT:
+ i = (**e1 << 24) | ((*e1)[1]) << 16| ((*e1)[2]) << 8| ((*e1)[3]) ;
+ *e1 += 4;
+ j = (**e2 << 24) | ((*e2)[1]) << 16| ((*e2)[2]) << 8| ((*e2)[3]) ;
+ *e2 += 4;
+ if (i < j) return -1;
+ if (i > j ) return 1;
+ while (i--) {
+ if ((j = compare_top_ext(e1, e2))) return j;
+ }
+ return 0;
+ case ERL_FLOAT_EXT:
+ if (sscanf((char *) *e1, "%lf", &ff1) != 1)
+ return -1;
+ *e1 += 31;
+ if (sscanf((char *) *e2, "%lf", &ff2) != 1)
+ return -1;
+ *e2 += 31;
+ return cmp_floats(ff1,ff2);
+
+ case ERL_BINARY_EXT:
+ i = (**e1 << 24) | ((*e1)[1] << 16) |((*e1)[2] << 8) | (*e1)[3];
+ *e1 += 4;
+ j = (**e2 << 24) | ((*e2)[1] << 16) |((*e2)[2] << 8) | (*e2)[3];
+ *e2 += 4;
+ ret = cmpbytes(*e1, i , *e2 , j);
+ *e1 += i; *e2 += j;
+ return ret;
+
+ case ERL_FUN_EXT: /* FIXME: */
+ case ERL_NEW_FUN_EXT: /* FIXME: */
+ return -1;
+
+ default:
+ return cmpbytes(*e1, 1, *e2, 1);
+
+ } /* switch */
+
+} /* cmp_exe2 */
+
+/* Number compare */
+
+static int cmp_floats(double f1, double f2)
+{
+#if defined(VXWORKS) && CPU == PPC860
+ return erl_fp_compare((unsigned *) &f1, (unsigned *) &f2);
+#else
+ if (f1<f2) return -1;
+ else if (f1>f2) return 1;
+ else return 0;
+#endif
+}
+
+static INLINE double to_float(long l)
+{
+ double f;
+#if defined(VXWORKS) && CPU == PPC860
+ erl_long_to_fp(l, (unsigned *) &f);
+#else
+ f = l;
+#endif
+ return f;
+}
+
+
+static int cmp_small_big(unsigned char**e1, unsigned char **e2)
+{
+ int i1,i2;
+ int t2;
+ int n2;
+ long l1;
+ int res;
+
+ erlang_big *b1,*b2;
+
+ i1 = i2 = 0;
+ if ( ei_decode_long((char *)*e1,&i1,&l1) < 0 ) return -1;
+
+ ei_get_type((char *)*e2,&i2,&t2,&n2);
+
+ /* any small will fit in two digits */
+ if ( (b1 = ei_alloc_big(2)) == NULL ) return -1;
+ if ( ei_small_to_big(l1,b1) < 0 ) {
+ ei_free_big(b1);
+ return -1;
+ }
+
+ if ( (b2 = ei_alloc_big(n2)) == NULL ) {
+ ei_free_big(b1);
+ return 1;
+ }
+
+ if ( ei_decode_big((char *)*e2,&i2,b2) < 0 ) {
+ ei_free_big(b1);
+ ei_free_big(b2);
+ return 1;
+ }
+
+ res = ei_big_comp(b1,b2);
+
+ ei_free_big(b1);
+ ei_free_big(b2);
+
+ *e1 += i1;
+ *e2 += i2;
+
+ return res;
+}
+
+static int cmp_small_float(unsigned char**e1, unsigned char **e2)
+{
+ int i1,i2;
+ long l1;
+ double f1,f2;
+
+ /* small -> float -> float_comp */
+
+ i1 = i2 = 0;
+ if ( ei_decode_long((char *)*e1,&i1,&l1) < 0 ) return -1;
+ if ( ei_decode_double((char *)*e2,&i2,&f2) < 0 ) return 1;
+
+ f1 = to_float(l1);
+
+ *e1 += i1;
+ *e2 += i2;
+
+ return cmp_floats(f1,f2);
+}
+
+static int cmp_float_big(unsigned char**e1, unsigned char **e2)
+{
+ int res;
+ int i1,i2;
+ int t2,n2;
+ double f1,f2;
+ erlang_big *b2;
+
+ /* big -> float if overflow return big sign else float_comp */
+
+ i1 = i2 = 0;
+ if ( ei_decode_double((char *)*e1,&i1,&f1) < 0 ) return -1;
+
+ if (ei_get_type((char *)*e2,&i2,&t2,&n2) < 0) return 1;
+ if ((b2 = ei_alloc_big(n2)) == NULL) return 1;
+ if (ei_decode_big((char *)*e2,&i2,b2) < 0) return 1;
+
+ /* convert the big to float */
+ if ( ei_big_to_double(b2,&f2) < 0 ) {
+ /* exception look at the sign */
+ res = b2->is_neg ? 1 : -1;
+ ei_free_big(b2);
+ return res;
+ }
+
+ ei_free_big(b2);
+
+ *e1 += i1;
+ *e2 += i2;
+
+ return cmp_floats(f1,f2);
+}
+
+static int cmp_small_small(unsigned char**e1, unsigned char **e2)
+{
+ int i1,i2;
+ long l1,l2;
+
+ i1 = i2 = 0;
+ if ( ei_decode_long((char *)*e1,&i1,&l1) < 0 ) {
+ fprintf(stderr,"Failed to decode 1\r\n");
+ return -1;
+ }
+ if ( ei_decode_long((char *)*e2,&i2,&l2) < 0 ) {
+ fprintf(stderr,"Failed to decode 2\r\n");
+ return 1;
+ }
+
+ *e1 += i1;
+ *e2 += i2;
+
+ if ( l1 < l2 ) return -1;
+ else if ( l1 > l2 ) return 1;
+ else return 0;
+}
+
+static int cmp_float_float(unsigned char**e1, unsigned char **e2)
+{
+ int i1,i2;
+ double f1,f2;
+
+ i1 = i2 = 0;
+ if ( ei_decode_double((char *)*e1,&i1,&f1) < 0 ) return -1;
+ if ( ei_decode_double((char *)*e2,&i2,&f2) < 0 ) return 1;
+
+ *e1 += i1;
+ *e2 += i2;
+
+ return cmp_floats(f1,f2);
+}
+
+static int cmp_big_big(unsigned char**e1, unsigned char **e2)
+{
+ int res;
+ int i1,i2;
+ int t1,t2;
+ int n1,n2;
+ erlang_big *b1,*b2;
+
+ i1 = i2 = 0;
+ ei_get_type((char *)*e1,&i1,&t1,&n1);
+ ei_get_type((char *)*e2,&i2,&t2,&n2);
+
+ b1 = ei_alloc_big(n1);
+ b2 = ei_alloc_big(n2);
+
+ ei_decode_big((char *)*e1,&i1,b1);
+ ei_decode_big((char *)*e2,&i2,b2);
+
+ res = ei_big_comp(b1,b2);
+
+ ei_free_big(b1);
+ ei_free_big(b2);
+
+ *e1 += i1;
+ *e2 += i2;
+
+ return res;
+}
+
+static int cmp_number(unsigned char**e1, unsigned char **e2)
+{
+ switch (CMP_NUM_CODE(**e1,**e2)) {
+
+ case SMALL_BIG:
+ /* fprintf(stderr,"compare small_big\r\n"); */
+ return cmp_small_big(e1,e2);
+
+ case BIG_SMALL:
+ /* fprintf(stderr,"compare sbig_small\r\n"); */
+ return -cmp_small_big(e2,e1);
+
+ case SMALL_FLOAT:
+ /* fprintf(stderr,"compare small_float\r\n"); */
+ return cmp_small_float(e1,e2);
+
+ case FLOAT_SMALL:
+ /* fprintf(stderr,"compare float_small\r\n"); */
+ return -cmp_small_float(e2,e1);
+
+ case FLOAT_BIG:
+ /* fprintf(stderr,"compare float_big\r\n"); */
+ return cmp_float_big(e1,e2);
+
+ case BIG_FLOAT:
+ /* fprintf(stderr,"compare big_float\r\n"); */
+ return -cmp_float_big(e2,e1);
+
+ case SMALL_SMALL:
+ /* fprintf(stderr,"compare small_small\r\n"); */
+ return cmp_small_small(e1,e2);
+
+ case FLOAT_FLOAT:
+ /* fprintf(stderr,"compare float_float\r\n"); */
+ return cmp_float_float(e1,e2);
+
+ case BIG_BIG:
+ /* fprintf(stderr,"compare big_big\r\n"); */
+ return cmp_big_big(e1,e2);
+
+ default:
+ /* should never get here ... */
+ /* fprintf(stderr,"compare standard\r\n"); */
+ return cmp_exe2(e1,e2);
+ }
+
+}
+
+/*
+ * If the arrays are of the same type, then we
+ * have to do a real compare.
+ */
+/*
+ * COMPARE TWO encoded BYTE ARRAYS e1 and e2.
+ * Return: -1 if e1 < e2
+ * 0 if e1 == e2
+ * 1 if e2 > e1
+ */
+static int compare_top_ext(unsigned char**e1, unsigned char **e2)
+{
+ if (**e1 == ERL_VERSION_MAGIC) (*e1)++;
+ if (**e2 == ERL_VERSION_MAGIC) (*e2)++;
+
+ if (cmp_array[**e1] < cmp_array[**e2]) return -1;
+ if (cmp_array[**e1] > cmp_array[**e2]) return 1;
+
+ if (IS_ERL_NUM(**e1))
+ return cmp_number(e1,e2);
+
+ if (cmp_array[**e1] == ERL_REF_CMP)
+ return cmp_refs(e1, e2);
+
+ return cmp_exe2(e1, e2);
+}
+
+int erl_compare_ext(unsigned char *e1, unsigned char *e2)
+{
+ return compare_top_ext(&e1, &e2);
+} /* erl_compare_ext */
+
+#if defined(VXWORKS) && CPU == PPC860
+/* FIXME we have no floating point but don't we have emulation?! */
+int erl_fp_compare(unsigned *a, unsigned *b)
+{
+ /* Big endian mode of powerPC, IEEE floating point. */
+ unsigned a_split[4] = {a[0] >> 31, /* Sign bit */
+ (a[0] >> 20) & 0x7FFU, /* Exponent */
+ a[0] & 0xFFFFFU, /* Mantissa MS bits */
+ a[1]}; /* Mantissa LS bits */
+ unsigned b_split[4] = {b[0] >> 31,
+ (b[0] >> 20) & 0x7FFU,
+ b[0] & 0xFFFFFU,
+ b[1]};
+ int a_is_infinite, b_is_infinite;
+ int res;
+
+
+ /* Make -0 be +0 */
+ if (a_split[1] == 0 && a_split[2] == 0 && a_split[3] == 0)
+ a_split[0] = 0;
+ if (b_split[1] == 0 && b_split[2] == 0 && b_split[3] == 0)
+ b_split[0] = 0;
+ /* Check for infinity */
+ a_is_infinite = (a_split[1] == 0x7FFU && a_split[2] == 0 &&
+ a_split[3] == 0);
+ b_is_infinite = (b_split[1] == 0x7FFU && b_split[2] == 0 &&
+ b_split[3] == 0);
+
+ if (a_is_infinite && !b_is_infinite)
+ return (a_split[0]) ? -1 : 1;
+ if (b_is_infinite && !a_is_infinite)
+ return (b_split[0]) ? 1 : -1;
+ if (a_is_infinite && b_is_infinite)
+ return b[0] - a[0];
+ /* Check for indeterminate or nan, infinite is already handled,
+ so we only check the exponent. */
+ if((a_split[1] == 0x7FFU) || (b_split[1] == 0x7FFU))
+ return INT_MAX; /* Well, they are not equal anyway,
+ abort() could be an alternative... */
+
+ if (a_split[0] && !b_split[0])
+ return -1;
+ if (b_split[0] && !a_split[0])
+ return 1;
+ /* Compare */
+ res = memcmp(a_split + 1, b_split + 1, 3 * sizeof(unsigned));
+ /* Make -1, 0 or 1 */
+ res = (!!res) * ((res < 0) ? -1 : 1);
+ /* Turn sign if negative values */
+ if (a_split[0]) /* Both are negative */
+ res = -1 * res;
+ return res;
+}
+
+static void join(unsigned d_split[4], unsigned *d)
+{
+ d[0] = (d_split[0] << 31) | /* Sign bit */
+ ((d_split[1] & 0x7FFU) << 20) | /* Exponent */
+ (d_split[2] & 0xFFFFFU); /* Mantissa MS bits */
+ d[1] = d_split[3]; /* Mantissa LS bits */
+}
+
+static int blength(unsigned long l)
+{
+ int i;
+ for(i = 0; l; ++i)
+ l >>= 1;
+ return i;
+}
+
+static void erl_long_to_fp(long l, unsigned *d)
+{
+ unsigned d_split[4];
+ unsigned x;
+ if (l < 0) {
+ d_split[0] = 1;
+ x = -l;
+ } else {
+ d_split[0] = 0;
+ x = l;
+ }
+
+ if (!l) {
+ memset(d_split,0,sizeof(d_split));
+ } else {
+ int len = blength(x);
+ x <<= (33 - len);
+ d_split[2] = (x >> 12);
+ d_split[3] = (x << 20);
+ d_split[1] = 1023 + len - 1;
+ }
+ join(d_split,d);
+}
+
+#endif
+
+
+/*
+ * Checks if a term is a "string": a flat list of byte-sized integers.
+ *
+ * Returns: 0 if the term is not a string, otherwise the length is returned.
+ */
+
+static int is_string(ETERM* term)
+{
+ int len = 0;
+
+ while (ERL_TYPE(term) == ERL_LIST) {
+ ETERM* head = HEAD(term);
+
+ if (!ERL_IS_INTEGER(head) || ((unsigned)head->uval.ival.i) > 255) {
+ return 0;
+ }
+ len++;
+ term = TAIL(term);
+ }
+
+ if (ERL_IS_EMPTY_LIST(term)) {
+ return len;
+ }
+ return 0;
+}
diff --git a/lib/erl_interface/src/legacy/erl_marshal.h b/lib/erl_interface/src/legacy/erl_marshal.h
new file mode 100644
index 0000000000..8b3c3b6fa1
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_marshal.h
@@ -0,0 +1,29 @@
+/*
+ * %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%
+ */
+#ifndef _ERL_MARSHALL_H
+#define _ERL_MARSHALL_H
+
+#include "erl_eterm.h" /* FIXME don't want to include this here */
+
+/* FIXME: not documented, may be internal */
+int erl_verify_magic(unsigned char*);
+void erl_init_marshal(void);
+int erl_encode_it(ETERM *ep, unsigned char **ext, int dist);
+
+#endif /* _ERL_MARSHALL_H */
diff --git a/lib/erl_interface/src/legacy/erl_resolve.c b/lib/erl_interface/src/legacy/erl_resolve.c
new file mode 100644
index 0000000000..7dfebb78ed
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_resolve.c
@@ -0,0 +1,106 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2003-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/***************************************************************************
+ *
+ * Compatibility with the old erl_interface library that had some
+ * undocumented functions.
+ *
+ ***************************************************************************/
+
+#include "eidef.h"
+
+#include "erl_interface.h"
+#include "ei_resolve.h"
+#include "ei_connect_int.h"
+#include "ei_epmd.h"
+
+struct hostent *erl_gethostbyname(const char *name)
+{
+ return ei_gethostbyname(name);
+}
+
+
+void erl_init_resolve(void)
+{
+ ei_init_resolve();
+}
+
+
+struct hostent *erl_gethostbyaddr(const char *addr, int len, int type)
+{
+ return ei_gethostbyaddr(addr, len, type);
+}
+
+
+struct hostent *erl_gethostbyname_r(const char *name,
+ struct hostent *hostp,
+ char *buffer,
+ int buflen,
+ int *h_errnop)
+{
+ return ei_gethostbyname_r(name,hostp,buffer,buflen,h_errnop);
+}
+
+
+struct hostent *erl_gethostbyaddr_r(const char *addr,
+ int length,
+ int type,
+ struct hostent *hostp,
+ char *buffer,
+ int buflen,
+ int *h_errnop)
+{
+ return ei_gethostbyaddr_r(addr,length,type,hostp,buffer,buflen,h_errnop);
+}
+
+
+int erl_distversion(int fd)
+{
+ return ei_distversion(fd);
+}
+
+int erl_epmd_connect(struct in_addr *inaddr)
+{
+ return ei_epmd_connect_tmo(inaddr,0);
+}
+
+int erl_epmd_port(struct in_addr *inaddr, const char *alive, int *dist)
+{
+ return ei_epmd_port(inaddr, alive, dist);
+}
+
+
+
+/* FIXME !!!!!
+erl_epmd_port ei_epmd_port
+erl_mutex_lock ei_mutex_lock
+erl_malloc erl_free ????
+erl_publish erl_unpublish
+< extern int erl_epmd_connect(struct in_addr *inaddr);
+< extern int erl_epmd_publish(int port, const char *alive);
+< extern int erl_epmd_port(struct in_addr *inaddr, const char *alive, int *dist);
+
+< int erl_unpublish(const char *alive)
+---
+> int ei_unpublish_alive(const char *alive)
+
+erl_self
+erl_getfdcookie
+*/
diff --git a/lib/erl_interface/src/legacy/erl_timeout.c b/lib/erl_interface/src/legacy/erl_timeout.c
new file mode 100644
index 0000000000..af1a4a1f3a
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_timeout.c
@@ -0,0 +1,161 @@
+/*
+ * %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%
+ */
+/* timeout.c
+ *
+ * todo: use posix timers (timer_create etc) instead of setitimer.
+ *
+ */
+#if !defined(__WIN32__) && !defined(VXWORKS)
+
+/* FIXME: well, at least I can compile now... */
+
+#include "eidef.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <signal.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#include "erl_timeout.h"
+
+typedef struct jmp_s {
+ jmp_buf jmpbuf;
+ struct itimerval timerinfo;
+ void *siginfo;
+ struct jmp_s *next;
+} *jmp_t;
+
+static jmp_t push(jmp_t j);
+static jmp_t pop(void);
+static void timeout_handler(int dummy);
+
+jmp_buf *timeout_setup(int ms)
+{
+ struct itimerval t;
+ jmp_t j;
+ void *s;
+
+#ifdef DEBUG
+ fprintf(stderr,"timeout setup\n");
+#endif
+ s=signal(SIGALRM,timeout_handler);
+
+ /* set the timer */
+ t.it_interval.tv_sec = 0;
+ t.it_interval.tv_usec = 0;
+ t.it_value.tv_sec = ms / 1000;
+ t.it_value.tv_usec = (ms % 1000) * 1000;
+
+ /* get a jump buffer and save it */
+ j = malloc(sizeof(*j)); /* FIXME check result */
+ j->siginfo = s;
+ push(j);
+
+ setitimer(ITIMER_REAL,&t,&(j->timerinfo));
+
+ return &(j->jmpbuf);
+}
+
+
+int timeout_cancel(void)
+{
+ jmp_t j;
+
+#ifdef DEBUG
+ fprintf(stderr,"timeout cancel\n");
+#endif
+ /* retrieve the jump buffer */
+ j=pop();
+ /* restore the timer and signal disposition */
+ setitimer(ITIMER_REAL,&(j->timerinfo),NULL);
+ signal(SIGALRM,j->siginfo);
+
+ free(j);
+
+ return 0;
+}
+
+void timeout_handler(int dummy)
+{
+ jmp_t j;
+
+#ifdef DEBUG
+ fprintf(stderr,"timeout handler\n");
+#endif
+
+ /* retrieve the jump buffer */
+ j=pop();
+
+ /* restore the timer and signal disposition */
+ setitimer(ITIMER_REAL,&(j->timerinfo),NULL);
+ signal(SIGALRM,j->siginfo);
+
+ free(j);
+ longjmp(j->jmpbuf,JMPVAL);
+ return; /* not reached */
+}
+
+
+/* a simple stack for saving the jump buffer allows us to pass a
+ * variable between functions that don't call each other, in a way
+ * that will survive the longjmp().
+ */
+
+/* FIXME problem for threaded ? */
+static jmp_t jmp_head=NULL;
+#ifdef DEBUG
+static int depth = 0;
+static int maxdepth = 0;
+#endif
+
+static jmp_t push(jmp_t j)
+{
+ j->next = jmp_head;
+ jmp_head = j;
+
+#ifdef DEBUG
+ depth++;
+ if (depth > maxdepth) maxdepth = depth;
+#endif
+
+ return j;
+}
+
+static jmp_t pop(void)
+{
+ jmp_t j = jmp_head;
+ if (j) jmp_head = j->next;
+#ifdef DEBUG
+ depth--;
+#endif
+ return j;
+}
+
+#endif /* platform */
diff --git a/lib/erl_interface/src/legacy/erl_timeout.h b/lib/erl_interface/src/legacy/erl_timeout.h
new file mode 100644
index 0000000000..4ef6d21a72
--- /dev/null
+++ b/lib/erl_interface/src/legacy/erl_timeout.h
@@ -0,0 +1,74 @@
+/*
+ * %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%
+ */
+#ifndef _ERL_TIMEOUT_H
+#define _ERL_TIMEOUT_H
+
+#if !defined (__WIN32__) && !defined (VXWORKS)
+
+#include <setjmp.h>
+
+/*
+ use timeout like this (delay in ms):
+
+ if (timeout(delay,fun(a,b,c))) {
+ printf("timeout occurred\n");
+ }
+ else {
+ ...
+ }
+
+If the call to fun() has not returned before 'delay' ms, it will be
+interrupted and and timeout() will return a non-zero value.
+
+If fun() finishes before 'delay' ms, then timeout will return 0.
+
+If you need the return value from fun then assign it like this:
+
+ if (timeout(delay,(x = fun(...)))) {
+ }
+
+These functions work by setting and catching SIGALRM, and although it
+saves and restores the signal handler, it may not work in situations
+where you are already using SIGALRM (this includes calls to sleep(3)).
+
+Note that although recursive calls to timeout will not fail, they may
+not give the expected results. All invocations of timeout use the same
+timer, which is set on entrance to timeout and restored on exit from
+timeout. So although an inner call to timeout will restart the timer
+for any pending outer call when it exits, any time that has already
+elapsed against the outer timeout is forgotten. In addition, the alarm
+signal will always go to the innermost (last called) timeout, which
+may or may not be the intention in recursive cases.
+
+*/
+
+#define JMPVAL 997 /* magic */
+
+#define timeout(ms,funcall) \
+ (setjmp(*timeout_setup(ms)) == JMPVAL ? -1: \
+ ((void)(funcall), timeout_cancel()))
+
+
+/* don't call any of these directly - use the macro! see above! */
+jmp_buf *timeout_setup(int ms);
+int timeout_cancel(void);
+
+#endif /* WIN32 && VXWORKS */
+
+#endif /* _ERL_TIMEOUT_H */
diff --git a/lib/erl_interface/src/legacy/global_names.c b/lib/erl_interface/src/legacy/global_names.c
new file mode 100644
index 0000000000..7333d94931
--- /dev/null
+++ b/lib/erl_interface/src/legacy/global_names.c
@@ -0,0 +1,109 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "eisend.h"
+#include "eirecv.h"
+#include "ei_connect_int.h"
+#include "erl_interface.h"
+#include "erl_connect.h"
+
+#define GLOBALNAMEBUF (16*1024) /* not very small actually */
+
+/* return a list of all registered names. Function allocates and
+ * returns a NULL-terminated array of pointers to strings. The caller
+ * is responsible for freeing the array. Space for the array and
+ * all strings is allocated with a single call to malloc, so the
+ * caller can make one call to free().
+ */
+/* global:registered_names() -> [name1,name2,...] */
+char **erl_global_names(int fd, int *count)
+{
+ char buf[GLOBALNAMEBUF];
+ char *bufp=buf;
+ char tmpbuf[64];
+ int size = 0;
+ int index = 0;
+ erlang_pid *self = erl_self();
+ erlang_msg msg;
+ int i;
+ int version;
+ int arity;
+ int msglen;
+ char **names;
+ char *s;
+
+ self->num = fd;
+ ei_encode_version(buf,&index);
+ ei_encode_tuple_header(buf,&index,2);
+ ei_encode_pid(buf,&index,self); /* PidFrom */
+ ei_encode_tuple_header(buf,&index,5);
+ ei_encode_atom(buf,&index,"call"); /* call */
+ ei_encode_atom(buf,&index,"global"); /* Mod */
+ ei_encode_atom(buf,&index,"registered_names"); /* Fun */
+ ei_encode_list_header(buf,&index,0); /* Args: [ ] */
+ ei_encode_atom(buf,&index,"user"); /* user */
+
+ /* make the rpc call */
+ if (ei_send_reg_encoded(fd,self,"rex",buf,index)) return NULL;
+
+ while (1) {
+ index = GLOBALNAMEBUF;
+ if (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue;
+ else break;
+ }
+
+ if (i != ERL_SEND) return NULL;
+
+ /* expecting { rex, [name1, name2, ...] } */
+ size = msglen;
+ index = 0;
+
+ if (ei_decode_version(buf,&index,&version)
+ || ei_decode_tuple_header(buf,&index,&arity)
+ || (arity != 2)
+ || ei_decode_atom(buf,&index,tmpbuf)
+ || strcmp(tmpbuf,"rex")
+ || ei_decode_list_header(buf,&index,&arity)) return NULL;
+
+
+ /* we use the size of the rest of the received message to estimate
+ * the buffer space required for all the strings. we know how many
+ * they are (arity) so we need space for that many pointers, plus
+ * a little less than the atoms themselves needed in the reply.
+ */
+ arity++; /* we will need a terminating NULL as well */
+ if (!(names = malloc((arity * sizeof(char**)) + (size-index)))) return NULL;
+
+ /* arity pointers first, followed by s */
+ s = (char *)(names+arity+1);
+
+ if (count) *count = 0;
+ for (i=0; i<arity; i++) {
+ names[i] = s; /* insert the pointer */
+ if (ei_decode_atom(buf,&index,s)) break; /* copy the data */
+ if (count) (*count)++;
+ s += strlen(names[i]) + 1; /* advance pointer */
+ }
+ names[i]=NULL;
+
+ return names;
+}
diff --git a/lib/erl_interface/src/legacy/global_register.c b/lib/erl_interface/src/legacy/global_register.c
new file mode 100644
index 0000000000..3a4de8b08e
--- /dev/null
+++ b/lib/erl_interface/src/legacy/global_register.c
@@ -0,0 +1,110 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "eisend.h"
+#include "eirecv.h"
+#include "erl_interface.h"
+
+int erl_global_register(int fd, const char *name, ETERM *pid)
+{
+ char buf[EISMALLBUF];
+ char *bufp=buf;
+ char tmpbuf[64];
+ int index = 0;
+ erlang_pid self;
+ erlang_msg msg;
+ int needlink, needatom;
+ int arity;
+ int version;
+ int msglen;
+ int i;
+
+ /* get that pid into a better format */
+ if (!erl_encode(pid,(unsigned char*)buf)) return -1;
+ if (ei_decode_version(buf,&index,&version)
+ || ei_decode_pid(buf,&index,&self)) return -1;
+
+ /* set up rpc arguments */
+ /* { PidFrom, { call, Mod, Fun, Args, user }} */
+ index = 0;
+ ei_encode_version(buf,&index);
+ ei_encode_tuple_header(buf,&index,2);
+ ei_encode_pid(buf,&index,&self); /* PidFrom */
+ ei_encode_tuple_header(buf,&index,5);
+ ei_encode_atom(buf,&index,"call"); /* call */
+ ei_encode_atom(buf,&index,"global"); /* Mod */
+ ei_encode_atom(buf,&index,"register_name_external"); /* Fun */
+ ei_encode_list_header(buf,&index,3); /* Args: [ name, self(), cnode ] */
+ ei_encode_atom(buf,&index,name);
+ ei_encode_pid(buf,&index,&self);
+ ei_encode_tuple_header(buf,&index,2);
+ ei_encode_atom(buf,&index,"global"); /* special "resolve" treatment */
+ ei_encode_atom(buf,&index,"cnode"); /* i.e. we get a SEND when conflict */
+ ei_encode_empty_list(buf,&index);
+ ei_encode_atom(buf,&index,"user"); /* user */
+
+ /* make the rpc call */
+ if (ei_send_reg_encoded(fd,&self,"rex",buf,index)) return -1;
+
+ /* get the reply: expect link and an atom, or just an atom */
+ needlink = needatom = 1;
+ while (1) {
+ /* get message */
+ while (1) {
+ index = EISMALLBUF;
+ if (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue;
+ else break;
+ }
+
+ switch (i) {
+ case ERL_LINK:
+ /* got link */
+ if (!needlink) return -1;
+ needlink = 0;
+ break;
+
+ case ERL_SEND:
+ /* got message - does it contain our atom? */
+ if (!needatom) return -1;
+ else {
+ /* expecting { rex, yes } */
+ index = 0;
+ if (ei_decode_version(buf,&index,&version)
+ || ei_decode_tuple_header(buf,&index,&arity)
+ || (arity != 2)
+ || ei_decode_atom(buf,&index,tmpbuf)
+ || strcmp(tmpbuf,"rex")
+ || ei_decode_atom(buf,&index,tmpbuf)
+ || strcmp(tmpbuf,"yes"))
+ return -1; /* bad response from other side */
+
+ /* we're done */
+ return 0;
+ }
+ break;
+
+ default:
+ return -1; /* something else */
+ }
+ }
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/legacy/global_unregister.c b/lib/erl_interface/src/legacy/global_unregister.c
new file mode 100644
index 0000000000..514dbc3c68
--- /dev/null
+++ b/lib/erl_interface/src/legacy/global_unregister.c
@@ -0,0 +1,102 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <string.h>
+#include "eidef.h" /* Has to be first */
+#include "eiext.h"
+#include "eisend.h"
+#include "eirecv.h"
+#include "ei_connect_int.h"
+#include "erl_interface.h"
+#include "erl_connect.h"
+
+/* remove the association between name and its pid */
+/* global:unregister_name(name) -> ok */
+int erl_global_unregister(int fd, const char *name)
+{
+ char buf[EISMALLBUF];
+ char *bufp=buf;
+ char tmpbuf[64];
+ int index = 0;
+ erlang_pid *self = erl_self();
+ erlang_msg msg;
+ int i;
+ int version,arity,msglen;
+ int needunlink, needatom;
+
+ /* make a self pid */
+ self->num = fd;
+ ei_encode_version(buf,&index);
+ ei_encode_tuple_header(buf,&index,2);
+ ei_encode_pid(buf,&index,self); /* PidFrom */
+ ei_encode_tuple_header(buf,&index,5);
+ ei_encode_atom(buf,&index,"call"); /* call */
+ ei_encode_atom(buf,&index,"global"); /* Mod */
+ ei_encode_atom(buf,&index,"unregister_name_external"); /* Fun */
+ ei_encode_list_header(buf,&index,1); /* Args: [ name ] */
+ ei_encode_atom(buf,&index,name);
+ ei_encode_empty_list(buf,&index);
+ ei_encode_atom(buf,&index,"user"); /* user */
+
+ /* make the rpc call */
+ if (ei_send_reg_encoded(fd,self,"rex",buf,index)) return -1;
+
+ /* get the reply: expect unlink and an atom, or just an atom */
+ needunlink = needatom = 1;
+ while (1) {
+ /* get message */
+ while (1) {
+ index = EISMALLBUF;
+ if (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue;
+ else break;
+ }
+
+ switch (i) {
+ case ERL_UNLINK:
+ /* got link */
+ if (!needunlink) return -1;
+ needunlink = 0;
+ break;
+
+ case ERL_SEND:
+ /* got message - does it contain our atom? */
+ if (!needatom) return -1;
+ else {
+ /* expecting { rex, ok } */
+ index = 0;
+ if (ei_decode_version(buf,&index,&version)
+ || ei_decode_tuple_header(buf,&index,&arity)
+ || (arity != 2)
+ || ei_decode_atom(buf,&index,tmpbuf)
+ || strcmp(tmpbuf,"rex")
+ || ei_decode_atom(buf,&index,tmpbuf)
+ || strcmp(tmpbuf,"ok"))
+ return -1; /* bad response from other side */
+
+ /* we're done here */
+ return 0;
+ }
+ break;
+
+ default:
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/legacy/global_whereis.c b/lib/erl_interface/src/legacy/global_whereis.c
new file mode 100644
index 0000000000..2afb193504
--- /dev/null
+++ b/lib/erl_interface/src/legacy/global_whereis.c
@@ -0,0 +1,91 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "eisend.h"
+#include "eirecv.h"
+#include "ei_connect_int.h"
+#include "erl_interface.h"
+#include "erl_connect.h"
+
+/* return the ETERM pid corresponding to name. If caller
+ * provides non-NULL node, nodename will be returned there
+ */
+/* global:whereis_name(name) -> pid */
+
+ETERM *erl_global_whereis(int fd, const char *name, char *node)
+{
+ char buf[EISMALLBUF];
+ char *bufp=buf;
+ char tmpbuf[64];
+ int index = 0;
+ erlang_pid *self = erl_self();
+ erlang_pid epid;
+ ETERM *opid;
+ erlang_msg msg;
+ int i;
+ int version,arity,msglen;
+
+ self->num = fd; /* FIXME looks strange to change something?! */
+
+ ei_encode_version(buf,&index);
+ ei_encode_tuple_header(buf,&index,2);
+ ei_encode_pid(buf,&index,self); /* PidFrom */
+ ei_encode_tuple_header(buf,&index,5);
+ ei_encode_atom(buf,&index,"call"); /* call */
+ ei_encode_atom(buf,&index,"global"); /* Mod */
+ ei_encode_atom(buf,&index,"whereis_name"); /* Fun */
+ ei_encode_list_header(buf,&index,1); /* Args: [ name ] */
+ ei_encode_atom(buf,&index,name);
+ ei_encode_empty_list(buf,&index);
+ ei_encode_atom(buf,&index,"user"); /* user */
+
+ /* make the rpc call */
+ if (ei_send_reg_encoded(fd,self,"rex",buf,index)) return NULL;
+
+ while (1) {
+ index = EISMALLBUF;
+ if (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue;
+ else break;
+ }
+
+ if (i != ERL_SEND) return NULL;
+
+ /* expecting { rex, pid } */
+ index = 0;
+ if (ei_decode_version(buf,&index,&version)
+ || ei_decode_tuple_header(buf,&index,&arity)
+ || (arity != 2)
+ || ei_decode_atom(buf,&index,tmpbuf)
+ || strcmp(tmpbuf,"rex")
+ || ei_decode_pid(buf,&index,&epid))
+ return NULL; /* bad response from other side */
+
+ /* put the pid into a format for the caller */
+ index = 0;
+ ei_encode_pid(buf,&index,&epid);
+ opid = erl_decode((unsigned char*)buf);
+
+ /* extract the nodename for the caller */
+ if (node) strcpy(node,epid.node);
+
+ return opid;
+}
diff --git a/lib/erl_interface/src/legacy/portability.h b/lib/erl_interface/src/legacy/portability.h
new file mode 100644
index 0000000000..5f984b08e1
--- /dev/null
+++ b/lib/erl_interface/src/legacy/portability.h
@@ -0,0 +1,33 @@
+/*
+ * %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%
+ */
+
+#ifndef _PORTABILITY_H
+#define _PORTABILITY_H
+
+#if !defined(__GNUC__) || __GNUC__ < 2
+
+/*
+ * GCC's attributes are too useful to not use. Other compilers
+ * just lose opportunities to optimize and warn.
+ */
+# define __attribute__(foo) /* nothing */
+
+#endif
+
+#endif /* _PORTABILITY_H */
diff --git a/lib/erl_interface/src/misc/ei_compat.c b/lib/erl_interface/src/misc/ei_compat.c
new file mode 100644
index 0000000000..45ea6e3a72
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_compat.c
@@ -0,0 +1,39 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2004-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%
+ *
+
+ */
+#include "ei.h"
+#include "ei_internal.h"
+
+#define EI_COMPAT_NO_REL (~((unsigned) 0))
+
+static unsigned compat_rel = EI_COMPAT_NO_REL;
+
+void
+ei_set_compat_rel(unsigned rel)
+{
+ if (compat_rel == EI_COMPAT_NO_REL)
+ compat_rel = rel;
+}
+
+int
+ei_internal_use_r9_pids_ports(void)
+{
+ return compat_rel < 10;
+}
diff --git a/lib/erl_interface/src/misc/ei_decode_term.c b/lib/erl_interface/src/misc/ei_decode_term.c
new file mode 100644
index 0000000000..7b95ff232f
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_decode_term.c
@@ -0,0 +1,156 @@
+/*
+ * %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%
+ *
+
+ */
+#include <string.h>
+
+#include "eidef.h"
+#include "eiext.h"
+#include "ei_decode_term.h"
+#include "putget.h"
+
+/* Returns 1 if term is decoded, 0 if term is OK, but not decoded here
+ and -1 if something is wrong.
+ ONLY changes index if term is decoded (return value 1)! */
+
+int ei_decode_ei_term(const char* buf, int* index, ei_term* term)
+{
+ const char* s = buf + *index, * s0 = s;
+ int len, i, n, sign;
+ char c;
+ double f;
+
+ if (term == NULL) return -1;
+ c = term->ei_type = get8(s);
+ switch (c) {
+ case ERL_SMALL_INTEGER_EXT:
+ term->value.i_val = get8(s);
+ break;
+ case ERL_INTEGER_EXT:
+ term->value.i_val = get32be(s);
+ break;
+ case ERL_FLOAT_EXT:
+ if (s[30]) return -1;
+ if (sscanf(s, "%lf", &f) != 1) return -1;
+ s += 31;
+ term->value.d_val = f;
+ break;
+ case ERL_ATOM_EXT:
+ len = get16be(s);
+ memcpy(term->value.atom_name, s, len);
+ term->value.atom_name[len] = '\0';
+ s += len;
+ break;
+ case ERL_REFERENCE_EXT:
+ /* first the nodename */
+ if (get8(s) != ERL_ATOM_EXT) return -1;
+ len = get16be(s);
+ memcpy(term->value.ref.node, s, len);
+ term->value.ref.node[len] = '\0';
+ s += len;
+ /* now the numbers: num (4), creation (1) */
+ term->value.ref.n[0] = get32be(s);
+ term->value.ref.len = 1;
+ term->value.ref.creation = get8(s) & 0x03;
+ break;
+ case ERL_NEW_REFERENCE_EXT:
+ /* first the integer count */
+ term->value.ref.len = get16be(s);
+ /* then the nodename */
+ if (get8(s) != ERL_ATOM_EXT) return -1;
+ len = get16be(s);
+ memcpy(term->value.ref.node, s, len);
+ term->value.ref.node[len] = '\0';
+ s += len;
+ /* creation */
+ term->value.ref.creation = get8(s) & 0x03;
+ /* finally the id integers */
+ for (i = 0; (i<term->value.ref.len) && (i<3); i++) {
+ term->value.ref.n[i] = get32be(s);
+ }
+ if (term->value.ref.len > 3) {
+ s += 4 * (term->value.ref.len - 3);
+ }
+ break;
+ case ERL_PORT_EXT:
+ if (get8(s) != ERL_ATOM_EXT) return -1;
+ len = get16be(s);
+ memcpy(term->value.port.node, s, len);
+ term->value.port.node[len] = '\0';
+ term->value.port.id = get32be(s) & 0x0fffffff; /* 28 bits */;
+ term->value.port.creation = get8(s) & 0x03;
+ break;
+ case ERL_PID_EXT:
+ if (get8(s) != ERL_ATOM_EXT) return -1;
+ /* name first */
+ len = get16be(s);
+ memcpy(term->value.pid.node, s, len);
+ term->value.pid.node[len] = '\0';
+ s += len;
+ /* now the numbers: num (4), serial (4), creation (1) */
+ term->value.pid.num = get32be(s) & 0x7fff; /* 15 bits */
+ term->value.pid.serial = get32be(s) & 0x1fff; /* 13 bits */
+ term->value.pid.creation = get8(s) & 0x03; /* 2 bits */
+ break;
+ case ERL_SMALL_TUPLE_EXT:
+ term->arity = get8(s);
+ break; /*return 0;*/
+ case ERL_LARGE_TUPLE_EXT:
+ term->arity = get32be(s);
+ break; /*return 0;*/
+ case ERL_NIL_EXT:
+ term->arity = 0;
+ break;
+ case ERL_STRING_EXT:
+ term->size = get16be(s);
+ return 0;
+ case ERL_LIST_EXT:
+ term->arity = get32be(s);
+ break; /*return 0;*/
+ case ERL_BINARY_EXT:
+ term->size = get32be(s);
+ return 0;
+ case ERL_SMALL_BIG_EXT:
+ if ((term->arity = get8(s)) != 4) return -1;
+ sign = get8(s);
+ /* Little Endian, and n always positive, except for LONG_MIN */
+ n = get32le(s);
+ if (sign) {
+ /* check for overflow */
+ if ((n - 1) < 0) return -1;
+ n = -n;
+ } else {
+ /* check for overflow */
+ if (n < 0) return -1;
+ }
+ break;
+ case ERL_LARGE_BIG_EXT:
+ return 0;
+ case ERL_PASS_THROUGH:
+ return 0;
+ case ERL_NEW_CACHE:
+ return -1;
+ case ERL_CACHED_ATOM:
+ return -1;
+ default:
+ return -1;
+ }
+ *index += s-s0;
+ return 1;
+}
diff --git a/lib/erl_interface/src/misc/ei_decode_term.h b/lib/erl_interface/src/misc/ei_decode_term.h
new file mode 100644
index 0000000000..76a71ae0a6
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_decode_term.h
@@ -0,0 +1,31 @@
+/*
+ * %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%
+ *
+
+ */
+
+#ifndef _EI_DECODE_TERM_H
+#define _EI_DECODE_TERM_H
+
+/* Returns 1 if term is decoded, 0 if term is OK, but not decoded here
+ and -1 if something is wrong.
+ ONLY changes index if term is decoded (return value 1)! */
+
+int ei_decode_ei_term(const char* buf, int* index, ei_term* term);
+
+#endif /* _EI_DECODE_TERM_H */
diff --git a/lib/erl_interface/src/misc/ei_format.c b/lib/erl_interface/src/misc/ei_format.c
new file mode 100644
index 0000000000..08235d0ebe
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_format.c
@@ -0,0 +1,466 @@
+/*
+ * %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%
+ *
+
+ */
+/*
+ * Function:
+ * ei_format to build binary format terms a bit like printf
+ */
+
+#ifdef VXWORKS
+#include <vxWorks.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef VRTX
+#define __READY_EXTENSIONS__
+#include <errno.h>
+#endif
+
+#include "eidef.h"
+#include "ei_malloc.h"
+#include "ei_format.h"
+
+/*
+ * To avoid problems we read the variable number of arguments to an
+ * array of unions.
+ */
+union arg {
+ char* s;
+ long l;
+ unsigned long u;
+ double d;
+};
+
+static int eiformat(const char** s, union arg** args, ei_x_buff* x);
+
+/* forwards of parse functions */
+static int pformat(const char** fmt, union arg**, ei_x_buff* x);
+static int plist(const char** fmt, union arg**, ei_x_buff* x, int size);
+static int ptuple(const char** fmt, union arg**, ei_x_buff* x, int size);
+static int pquotedatom(const char** fmt, ei_x_buff* x);
+static int pdigit(const char** fmt, ei_x_buff* x);
+static int patom(const char** fmt, ei_x_buff* x);
+static int pstring(const char** fmt, ei_x_buff* x);
+
+/* format a string into an ei_x_buff, except the version token */
+static int eiformat(const char** fmt, union arg** args, ei_x_buff* x)
+{
+ const char* p = *fmt;
+ int res;
+ ei_x_buff x2;
+
+ while (isspace((int)*p))
+ ++p;
+ switch (*p) {
+ case '~':
+ res = pformat(&p, args, x);
+ break;
+ case '[':
+ res = ei_x_new(&x2);
+ if (res >= 0)
+ res = plist(&p, args, &x2, 0);
+ if (res > 0)
+ res = ei_x_encode_list_header(x, res);
+ if (res >= 0)
+ res = ei_x_append(x, &x2);
+ ei_x_free(&x2);
+ break;
+ case '{':
+ res = ei_x_new(&x2);
+ if (res >= 0)
+ res = ptuple(&p, args, &x2, 0);
+ if (res >= 0)
+ res = ei_x_encode_tuple_header(x, res);
+ if (res >= 0)
+ res = ei_x_append(x, &x2);
+ ei_x_free(&x2);
+ break;
+ case '"':
+ res = pstring(&p, x);
+ break;
+ case '\'':
+ res = pquotedatom(&p, x);
+ break;
+ default:
+ if (isdigit((int)*p))
+ res = pdigit(&p, x);
+ else if (islower((int)*p))
+ res = patom(&p, x);
+ else
+ res = -1;
+ break;
+ /*
+ Variables
+ */
+ }
+ *fmt = p;
+ return res;
+}
+
+static int patom(const char** fmt, ei_x_buff* x)
+{
+ const char* start = *fmt;
+ char c;
+ int len;
+
+ for (;;) {
+ c = *(*fmt)++;
+ if (isalnum((int) c) || (c == '_') || (c == '@'))
+ continue;
+ else
+ break;
+ }
+ --(*fmt);
+ len = *fmt - start;
+ /* FIXME why truncate atom name and not fail?! */
+ if (len > MAXATOMLEN)
+ len = MAXATOMLEN;
+ return ei_x_encode_atom_len(x, start, len);
+}
+
+/* Check if integer or float */
+static int pdigit(const char** fmt, ei_x_buff* x)
+{
+ const char* start = *fmt;
+ char c;
+ int len, dotp=0;
+ double d;
+ long l;
+
+ for (;;) {
+ c = *(*fmt)++;
+ if (isdigit((int)c))
+ continue;
+ else if (!dotp && (c == '.')) {
+ dotp = 1;
+ continue;
+ } else
+ break;
+ }
+ --(*fmt);
+ len = *fmt - start;
+ if (dotp) {
+ sscanf(start, "%lf", &d);
+ return ei_x_encode_double(x, d);
+ } else {
+ sscanf(start, "%ld", &l);
+ return ei_x_encode_long(x, l);
+ }
+}
+
+/* "string" */
+static int pstring(const char** fmt, ei_x_buff* x)
+{
+ const char* start = ++(*fmt); /* skip first quote */
+ char c;
+ int res;
+
+ for (;;) {
+ c = *(*fmt)++;
+ if (c == '\0')
+ return -1;
+ if (c == '"') {
+ if (*((*fmt)-1) == '\\')
+ continue;
+ else
+ break;
+ } else
+ continue;
+ }
+ res = ei_x_encode_string_len(x, start, *fmt - start - 1);
+ return res;
+}
+
+/* 'atom' */
+static int pquotedatom(const char** fmt, ei_x_buff* x)
+{
+ const char* start = ++(*fmt); /* skip first quote */
+ char c;
+ int res;
+
+ for (;;) {
+ c = *(*fmt)++;
+ if (c == 0)
+ return -1;
+ if (c == '\'') {
+ if (*((*fmt)-1) == '\\')
+ continue;
+ else
+ break;
+ } else
+ continue;
+ }
+ res = ei_x_encode_atom_len(x, start, *fmt - start - 1);
+ return res;
+}
+
+
+ /*
+ * The format letters are:
+ * a - An atom
+ * s - A string
+ * i - An integer
+ * l - A long integer
+ * u - An unsigned long integer
+ * f - A float
+ * d - A double float
+ */
+static int pformat(const char** fmt, union arg** args, ei_x_buff* x)
+{
+ int res = 0;
+ ++(*fmt); /* skip tilde */
+ switch (*(*fmt)++) {
+ case 'a':
+ res = ei_x_encode_atom(x, (*args)->s);
+ (*args)++;
+ break;
+ case 's':
+ res = ei_x_encode_string(x, (*args)->s);
+ (*args)++;
+ break;
+ case 'i':
+ res = ei_x_encode_long(x, (*args)->l);
+ (*args)++;
+ break;
+ case 'l':
+ res = ei_x_encode_long(x, (*args)->l);
+ (*args)++;
+ break;
+ case 'u':
+ res = ei_x_encode_ulong(x, (*args)->u);
+ (*args)++;
+ break;
+ case 'f': /* float is expanded to double (C calling conventions) */
+ case 'd':
+ res = ei_x_encode_double(x, (*args)->d);
+ (*args)++;
+ break;
+ default:
+ res = -1;
+ break;
+ }
+ return res;
+}
+
+/* encode a tuple */
+static int ptuple(const char** fmt, union arg** args, ei_x_buff* x, int size)
+{
+ int res = 0;
+ const char* p = *fmt;
+ char after = *p++;
+
+ if (after == '}') {
+ *fmt = p;
+ return size;
+ }
+ while (isspace((int)*p))
+ ++p;
+ switch (*p++) {
+ case '}':
+ if (after == ',')
+ res = -1;
+ else
+ res = size;
+ break;
+ case ',':
+ if (after == ',' || after == '{')
+ res = -1;
+ else
+ res = ptuple(&p, args, x, size);
+ break;
+ default:
+ --p;
+ res = eiformat(&p, args, x);
+ if (res >= 0)
+ res = ptuple(&p, args, x, size + 1);
+ break;
+ /*
+ Variables
+ */
+ }
+ *fmt = p;
+ return res;
+}
+
+/* encode a list */
+static int plist(const char** fmt, union arg** args, ei_x_buff* x, int size)
+{
+ int res = 0;
+ const char* p = *fmt;
+ char after = *p++;
+
+ if (after == ']')
+ --p;
+ while (isspace((int)*p))
+ ++p;
+ switch (*p++) {
+ case ']':
+ if (after == ',')
+ res = -1;
+ else {
+ if (after != '|')
+ ei_x_encode_empty_list(x);
+ res = size;
+ }
+ break;
+ case '|':
+ if (after == '|' || after == ',')
+ res = -1;
+ else
+ res = plist(&p, args, x, size);
+ break;
+ case ',':
+ if (after == '|' || after == ',')
+ res = -1;
+ else
+ res = plist(&p, args, x, size);
+ break;
+ default:
+ --p;
+ res = eiformat(&p, args, x);
+ ++size;
+ if (res >= 0) {
+ if (after == '|') {
+ while (isspace((int)*p))
+ ++p;
+ if (*p != ']')
+ res = -1;
+ } else
+ res = plist(&p, args, x, size);
+ }
+ break;
+ /*
+ Variables
+ */
+ }
+ *fmt = p;
+ return res;
+}
+
+static int read_args(const char* fmt, va_list ap, union arg **argp)
+{
+ const char* p = fmt;
+ int arg_count = 0;
+ union arg* args;
+ int i = 0;
+
+ /* Count the number of format strings. Assume null terminated string. */
+
+ *argp = NULL;
+
+ while (*p) if (*p++ == '~') arg_count++;
+
+
+ if (!arg_count) {
+ return 0;
+ }
+ /* Allocate space for the arguments */
+
+ args = (union arg*)ei_malloc(arg_count * sizeof(union arg));
+
+ if (!args)
+ return -1;
+
+ p = fmt; /* Start again and fill array */
+
+ while (*p) {
+ if (*p++ == '~') {
+ if (!*p) {
+ ei_free(args);
+ return -1; /* Error, string not complete */
+ }
+ switch (*p++) {
+ case 'a':
+ case 's':
+ args[i++].s = va_arg(ap, char*);
+ break;
+ case 'i':
+#ifdef EI_64BIT
+ args[i++].l = (long) va_arg(ap, int);
+ break;
+#endif
+ case 'l':
+ args[i++].l = va_arg(ap, long);
+ break;
+ case 'u':
+ args[i++].u = va_arg(ap, unsigned long);
+ break;
+ case 'f': /* float is expanded to double (C calling conventions) */
+ case 'd':
+ args[i++].d = va_arg(ap, double);
+ break;
+ default:
+ ei_free(args); /* Invalid specifier */
+ return -1;
+ }
+ }
+ }
+ *argp = args;
+ return 0;
+}
+
+int ei_x_format(ei_x_buff* x, const char* fmt, ... )
+{
+ va_list ap;
+ union arg* args;
+ union arg* saved_args;
+ int res;
+
+ res = ei_x_encode_version(x);
+ if (res < 0) return res;
+
+ va_start(ap, fmt);
+ res = read_args(fmt,ap,&args);
+ saved_args = args;
+ va_end(ap);
+ if (res < 0) {
+ return -1;
+ }
+
+ res = eiformat(&fmt, &args, x);
+ ei_free(saved_args);
+
+ return res;
+}
+
+int ei_x_format_wo_ver(ei_x_buff* x, const char* fmt, ... )
+{
+ va_list ap;
+ union arg* args;
+ union arg* saved_args;
+ int res;
+
+ va_start(ap, fmt);
+ res = read_args(fmt,ap,&args);
+ saved_args = args;
+ va_end(ap);
+ if (res < 0) {
+ return -1;
+ }
+ res = eiformat(&fmt, &args, x);
+ ei_free(saved_args);
+
+ return res;
+}
diff --git a/lib/erl_interface/src/misc/ei_format.h b/lib/erl_interface/src/misc/ei_format.h
new file mode 100644
index 0000000000..e94d0531f5
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_format.h
@@ -0,0 +1,26 @@
+/*
+ * %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%
+ *
+
+ */
+
+#ifndef _EI_FORMAT_H
+#define _EI_FORMAT_H
+
+#endif /* _EI_FORMAT_H */
+
diff --git a/lib/erl_interface/src/misc/ei_internal.h b/lib/erl_interface/src/misc/ei_internal.h
new file mode 100644
index 0000000000..9f51d1f61b
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_internal.h
@@ -0,0 +1,157 @@
+/*
+ * %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%
+ *
+
+ */
+#ifndef _EI_INTERNAL_H
+#define _EI_INTERNAL_H
+
+/*
+ * Some useful stuff not to be exported to users.
+ */
+
+#ifdef __WIN32__
+#define MAXPATHLEN 256
+#define writesocket(sock,buf,nbyte) send(sock,buf,nbyte,0)
+#define readsocket(sock,buf,nbyte) recv(sock,buf,nbyte,0)
+#else /* not __WIN32__ */
+#define writesocket write
+#define readsocket read
+#define closesocket close
+#define ioctlsocket ioctl
+#endif
+
+/*
+ * Trace functions
+ *
+ * The variable ei_tracelevel means
+ * 0 No tracing
+ * 1 Write verbose error messages
+ * 2 Write verbose warning messages + 1
+ * 3 Write progress reports for connect handlin + 1 + 2
+ * 4 Write progress reports for communication + 1 + 2 + 3
+ * 5 Write progress reports for data conversion + 1 + 2 + 3 + 4
+ *
+ */
+
+#define EI_TRACE_ERR0(NAME,FORMAT) \
+ {if (ei_tracelevel >= 1) ei_trace_printf(NAME,1,FORMAT);}
+#define EI_TRACE_ERR1(NAME,FORMAT,ARG1) \
+ {if (ei_tracelevel >= 1) ei_trace_printf(NAME,1,FORMAT,ARG1);}
+#define EI_TRACE_ERR2(NAME,FORMAT,ARG1,ARG2) \
+ {if (ei_tracelevel >= 1) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2);}
+#define EI_TRACE_ERR3(NAME,FORMAT,ARG1,ARG2,ARG3) \
+ {if (ei_tracelevel >= 1) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3);}
+#define EI_TRACE_ERR4(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4) \
+ {if (ei_tracelevel >= 1) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4);}
+#define EI_TRACE_ERR5(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5) \
+ {if (ei_tracelevel >= 1) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \
+ ARG5);}
+#define EI_TRACE_ERR6(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6) \
+ {if (ei_tracelevel >= 1) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \
+ ARG5,ARG6);}
+#define EI_TRACE_ERR7(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7) \
+ {if (ei_tracelevel >= 1) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \
+ ARG5,ARG6,ARG7);}
+
+#define EI_TRACE_WARN0(NAME,FORMAT) \
+ {if (ei_tracelevel >= 2) ei_trace_printf(NAME,1,FORMAT);}
+#define EI_TRACE_WARN1(NAME,FORMAT,ARG1) \
+ {if (ei_tracelevel >= 2) ei_trace_printf(NAME,1,FORMAT,ARG1);}
+#define EI_TRACE_WARN2(NAME,FORMAT,ARG1,ARG2) \
+ {if (ei_tracelevel >= 2) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2);}
+#define EI_TRACE_WARN3(NAME,FORMAT,ARG1,ARG2,ARG3) \
+ {if (ei_tracelevel >= 2) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3);}
+#define EI_TRACE_WARN4(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4) \
+ {if (ei_tracelevel >= 2) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4);}
+#define EI_TRACE_WARN5(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5) \
+ {if (ei_tracelevel >= 2) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \
+ ARG5);}
+#define EI_TRACE_WARN6(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6) \
+ {if (ei_tracelevel >= 2) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \
+ ARG5,ARG6);}
+#define EI_TRACE_WARN7(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7) \
+ {if (ei_tracelevel >= 2) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \
+ ARG5,ARG6,ARG7);}
+
+#define EI_TRACE_CONN0(NAME,FORMAT) \
+ {if (ei_tracelevel >= 3) ei_trace_printf(NAME,1,FORMAT);}
+#define EI_TRACE_CONN1(NAME,FORMAT,ARG1) \
+ {if (ei_tracelevel >= 3) ei_trace_printf(NAME,1,FORMAT,ARG1);}
+#define EI_TRACE_CONN2(NAME,FORMAT,ARG1,ARG2) \
+ {if (ei_tracelevel >= 3) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2);}
+#define EI_TRACE_CONN3(NAME,FORMAT,ARG1,ARG2,ARG3) \
+ {if (ei_tracelevel >= 3) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3);}
+#define EI_TRACE_CONN4(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4) \
+ {if (ei_tracelevel >= 3) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4);}
+#define EI_TRACE_CONN5(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5) \
+ {if (ei_tracelevel >= 3) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \
+ ARG5);}
+#define EI_TRACE_CONN6(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6) \
+ {if (ei_tracelevel >= 3) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \
+ ARG5,ARG6);}
+#define EI_TRACE_CONN7(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7) \
+ {if (ei_tracelevel >= 3) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \
+ ARG5,ARG6,ARG7);}
+
+#define EI_TRACE_COMM0(NAME,FORMAT) \
+ {if (ei_tracelevel >= 4) ei_trace_printf(NAME,1,FORMAT);}
+#define EI_TRACE_COMM1(NAME,FORMAT,ARG1) \
+ {if (ei_tracelevel >= 4) ei_trace_printf(NAME,1,FORMAT,ARG1);}
+#define EI_TRACE_COMM2(NAME,FORMAT,ARG1,ARG2) \
+ {if (ei_tracelevel >= 4) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2);}
+#define EI_TRACE_COMM3(NAME,FORMAT,ARG1,ARG2,ARG3) \
+ {if (ei_tracelevel >= 4) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3);}
+#define EI_TRACE_COMM4(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4) \
+ {if (ei_tracelevel >= 4) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4);}
+#define EI_TRACE_COMM5(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5) \
+ {if (ei_tracelevel >= 4) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \
+ ARG5);}
+#define EI_TRACE_COMM6(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6) \
+ {if (ei_tracelevel >= 4) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \
+ ARG5,ARG6);}
+#define EI_TRACE_COMM7(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7) \
+ {if (ei_tracelevel >= 4) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \
+ ARG5,ARG6,ARG7);}
+
+#define EI_TRACE0(NAME,FORMAT) \
+ {if (ei_tracelevel >= 5) ei_trace_printf(NAME,1,FORMAT);}
+#define EI_TRACE1(NAME,FORMAT,ARG1) \
+ {if (ei_tracelevel >= 5) ei_trace_printf(NAME,1,FORMAT,ARG1);}
+#define EI_TRACE2(NAME,FORMAT,ARG1,ARG2) \
+ {if (ei_tracelevel >= 5) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2);}
+#define EI_TRACE3(NAME,FORMAT,ARG1,ARG2,ARG3) \
+ {if (ei_tracelevel >= 5) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3);}
+#define EI_TRACE4(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4) \
+ {if (ei_tracelevel >= 5) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4);}
+#define EI_TRACE5(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5) \
+ {if (ei_tracelevel >= 5) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \
+ ARG5);}
+#define EI_TRACE6(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6) \
+ {if (ei_tracelevel >= 5) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \
+ ARG5,ARG6);}
+#define EI_TRACE7(NAME,FORMAT,ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7) \
+ {if (ei_tracelevel >= 5) ei_trace_printf(NAME,1,FORMAT,ARG1,ARG2,ARG3,ARG4, \
+ ARG5,ARG6,ARG7);}
+
+int ei_tracelevel;
+
+void ei_trace_printf(const char *name, int level, const char *format, ...);
+
+int ei_internal_use_r9_pids_ports(void);
+#endif /* _EI_INTERNAL_H */
diff --git a/lib/erl_interface/src/misc/ei_locking.c b/lib/erl_interface/src/misc/ei_locking.c
new file mode 100644
index 0000000000..e3f57d5ba2
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_locking.c
@@ -0,0 +1,164 @@
+/*
+ * %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%
+ *
+
+ */
+/*
+ * common interface to some simple synchronisation primitives for
+ * internal use by ei.
+ */
+
+/* Note that these locks are NOT recursive on Win32 or Solaris,
+ * i.e. self-deadlock will occur if a thread tries to obtain a lock it
+ * is already holding. The primitives used on VxWorks are recursive however.
+ */
+
+#include "eidef.h"
+
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+
+#elif VXWORKS
+#include <vxWorks.h>
+#include <semLib.h>
+
+#else /* unix */
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#endif /* platforms */
+
+#include "ei_malloc.h"
+#include "ei_locking.h"
+
+#ifdef _REENTRANT
+
+/*
+ * Create a new mutex object.
+ * Returns a pointer to the mutex if successful, NULL otherwise.
+ */
+ei_mutex_t *ei_mutex_create(void)
+{
+ ei_mutex_t *l;
+
+ if ((l = ei_malloc(sizeof(*l))) == NULL) return NULL;
+
+#ifdef __WIN32__
+ l->lock = CreateMutex(NULL,FALSE,NULL);
+
+#elif VXWORKS
+ if (!(l->lock = semMCreate(SEM_DELETE_SAFE))) {
+ ei_free(l);
+ return NULL;
+ }
+#else /* unix */
+ l->lock = ei_m_create();
+#endif
+
+ return l;
+}
+
+/*
+ * Free a mutex and the structure asociated with it.
+ *
+ * This function attempts to obtain the mutex before releasing it;
+ * If nblock == 1 and the mutex was unavailable, the function will
+ * return failure and the mutex will not have been removed.
+ *
+ * If nblock == 0 the function will block until the mutex becomes
+ * available, at which time it will be removed and the function will
+ * succeed.
+ *
+ * returns 0 if the mutex is removed, -1 on failure (busy)
+ */
+int ei_mutex_free(ei_mutex_t *l, int nblock)
+{
+ /* attempt to lock it first, to make sure it's really free */
+ if (ei_mutex_lock(l,nblock)) return -1; /* attempt failed */
+
+ /* we are now holding the lock */
+#ifdef __WIN32__
+ CloseHandle(l->lock);
+
+#elif VXWORKS
+ if (semDelete(l->lock) == ERROR) return -1;
+
+#else /* unix */
+ ei_m_destroy(l->lock);
+#endif
+
+ ei_free(l);
+
+ return 0;
+}
+
+/* Grab a mutex. If the mutex is not held by any other process the
+ * function returns so that the caller may enter a critical section.
+ * Processes subsequently wishing to obtain the lock will block
+ * until this process releases it.
+ *
+ * If the mutex is busy (held by some other process) and nblock == 0,
+ * the function will block until the mutex is freed by the process
+ * holding it, returning only when the mutex has been grabbed.
+ *
+ * If the mutex is busy and nblock != 0, the function will not block.
+ * Instead it will return -1 immediately, indicating that the
+ * operation failed.
+
+ * Returns 0 on success, -1 on failure.
+ */
+int ei_mutex_lock(ei_mutex_t *l, int nblock)
+{
+#ifdef __WIN32__
+ /* check valid values for timeout: is 0 ok? */
+ if (WaitForSingleObject(l->lock,(nblock? 0 : INFINITE)) != WAIT_OBJECT_0)
+ return -1;
+
+#elif VXWORKS
+ if (semTake(l->lock,(nblock? NO_WAIT : WAIT_FOREVER)) == ERROR)
+ return -1;
+
+#else /* unix */
+ if (nblock) {
+ if (ei_m_trylock(l->lock) < 0) return -1;
+ }
+ else ei_m_lock(l->lock);
+#endif
+
+ return 0;
+}
+
+/* Release a mutex */
+int ei_mutex_unlock(ei_mutex_t *l)
+{
+#ifdef __WIN32__
+ ReleaseMutex(l->lock);
+
+#elif VXWORKS
+ semGive(l->lock);
+
+#else /* unix */
+ ei_m_unlock(l->lock);
+#endif
+
+ return 0;
+}
+
+#endif /* _REENTRANT */
diff --git a/lib/erl_interface/src/misc/ei_locking.h b/lib/erl_interface/src/misc/ei_locking.h
new file mode 100644
index 0000000000..f97683e40d
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_locking.h
@@ -0,0 +1,76 @@
+/*
+ * %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%
+ *
+
+ */
+#ifndef _EI_LOCKING_H
+#define _EI_LOCKING_H
+
+#include "config.h"
+
+#if defined(VXWORKS)
+#include <taskLib.h>
+#include <taskVarLib.h>
+#endif
+
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+#endif
+
+#ifdef HAVE_MIT_PTHREAD_H
+#include <pthread/mit/pthread.h>
+#elif HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+
+
+typedef struct ei_mutex_s {
+#ifdef __WIN32__
+ HANDLE lock;
+#elif VXWORKS
+ SEM_ID lock;
+#else /* unix */
+#if defined(HAVE_MIT_PTHREAD_H) || defined(HAVE_PTHREAD_H)
+ pthread_mutex_t *lock;
+#else /* ! (HAVE_MIT_PTHREAD_H || HAVE_PTHREAD_H) */
+ void *dummy; /* Actually never used */
+#endif /* ! (HAVE_MIT_PTHREAD_H || HAVE_PTHREAD_H) */
+#endif /* unix */
+} ei_mutex_t;
+
+extern ei_mutex_t* ei_sockets_lock; /* FIXME global variable! */
+
+ei_mutex_t *ei_mutex_create(void);
+int ei_mutex_free(ei_mutex_t *l, int nblock);
+int ei_mutex_lock(ei_mutex_t *l, int nblock);
+int ei_mutex_unlock(ei_mutex_t *l);
+
+
+#if defined(_REENTRANT) && !defined(VXWORKS) && !defined(__WIN32__)
+
+void *ei_m_create(void);
+int ei_m_destroy(void *l);
+int ei_m_lock(void *l);
+int ei_m_trylock(void *l);
+int ei_m_unlock(void *l);
+
+#endif /* _REENTRANT && !VXWORKS && !__WIN32__ */
+
+#endif /* _EI_LOCKING_H */
diff --git a/lib/erl_interface/src/misc/ei_malloc.c b/lib/erl_interface/src/misc/ei_malloc.c
new file mode 100644
index 0000000000..b122c0f7b8
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_malloc.c
@@ -0,0 +1,41 @@
+/*
+ * %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%
+ *
+
+ */
+
+#include "eidef.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include "ei_malloc.h"
+
+void* ei_malloc (long size)
+{
+ return malloc(size);
+}
+
+void* ei_realloc(void* orig, long size)
+{
+ return realloc(orig, size);
+}
+
+void ei_free (void *ptr)
+{
+ free(ptr);
+}
diff --git a/lib/erl_interface/src/misc/ei_malloc.h b/lib/erl_interface/src/misc/ei_malloc.h
new file mode 100644
index 0000000000..ef8efaf9ea
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_malloc.h
@@ -0,0 +1,28 @@
+/*
+ * %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%
+ *
+
+ */
+#ifndef _EI_MALLOC_H
+#define _EI_MALLOC_H
+
+void* ei_malloc (long size);
+void* ei_realloc(void* orig, long size);
+void ei_free (void *ptr);
+
+#endif /* _EI_MALLOC_H */
diff --git a/lib/erl_interface/src/misc/ei_portio.c b/lib/erl_interface/src/misc/ei_portio.c
new file mode 100644
index 0000000000..b73ebebbe1
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_portio.c
@@ -0,0 +1,377 @@
+/*
+ * %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%
+ *
+
+ */
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <process.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+
+static unsigned long param_zero = 0;
+static unsigned long param_one = 1;
+#define SET_BLOCKING(Sock) ioctlsocket((Sock),FIONBIO,&param_zero)
+#define SET_NONBLOCKING(Sock) ioctlsocket((Sock),FIONBIO,&param_one)
+
+#define ERROR_WOULDBLOCK WSAEWOULDBLOCK
+#define ERROR_TIMEDOUT WSAETIMEDOUT
+#define ERROR_INPROGRESS WSAEINPROGRESS
+#define GET_SOCKET_ERROR() WSAGetLastError()
+#define MEANS_SOCKET_ERROR(Ret) ((Ret == SOCKET_ERROR))
+#define IS_INVALID_SOCKET(Sock) ((Sock) == INVALID_SOCKET)
+
+#elif VXWORKS
+#include <vxWorks.h>
+#include <hostLib.h>
+#include <ifLib.h>
+#include <sockLib.h>
+#include <taskLib.h>
+#include <inetLib.h>
+#include <selectLib.h>
+#include <sys/types.h>
+#include <ioLib.h>
+#include <unistd.h>
+
+static unsigned long param_zero = 0;
+static unsigned long param_one = 1;
+#define SET_BLOCKING(Sock) ioctl((Sock),FIONBIO,(int)&param_zero)
+#define SET_NONBLOCKING(Sock) ioctl((Sock),FIONBIO,(int)&param_one)
+#define ERROR_WOULDBLOCK EWOULDBLOCK
+#define ERROR_TIMEDOUT ETIMEDOUT
+#define ERROR_INPROGRESS EINPROGRESS
+#define GET_SOCKET_ERROR() (errno)
+#define MEANS_SOCKET_ERROR(Ret) ((Ret) == ERROR)
+#define IS_INVALID_SOCKET(Sock) ((Sock) < 0)
+
+#else /* other unix */
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifndef EWOULDBLOCK
+#define ERROR_WOULDBLOCK EAGAIN
+#else
+#define ERROR_WOULDBLOCK EWOULDBLOCK
+#endif
+#define SET_BLOCKING(fd) fcntl((fd), F_SETFL, \
+ fcntl((fd), F_GETFL, 0) & ~O_NONBLOCK)
+#define SET_NONBLOCKING(fd) fcntl((fd), F_SETFL, \
+ fcntl((fd), F_GETFL, 0) | O_NONBLOCK)
+#define ERROR_TIMEDOUT ETIMEDOUT
+#define ERROR_INPROGRESS EINPROGRESS
+#define GET_SOCKET_ERROR() (errno)
+#define MEANS_SOCKET_ERROR(Ret) ((Ret) < 0)
+#define IS_INVALID_SOCKET(Sock) ((Sock) < 0)
+
+#endif
+
+/* common includes */
+#include "eidef.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ei_portio.h"
+#include "ei_internal.h"
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+#ifdef HAVE_WRITEV
+static int ei_writev_t(int fd, struct iovec *iov, int iovcnt, unsigned ms)
+{
+ int res;
+ if (ms != 0) {
+ fd_set writemask;
+ struct timeval tv;
+ tv.tv_sec = (time_t) (ms / 1000U);
+ ms %= 1000U;
+ tv.tv_usec = (time_t) (ms * 1000U);
+ FD_ZERO(&writemask);
+ FD_SET(fd,&writemask);
+ switch (select(fd+1, NULL, &writemask, NULL, &tv)) {
+ case -1 :
+ return -1; /* i/o error */
+ case 0:
+ return -2; /* timeout */
+ default:
+ if (!FD_ISSET(fd, &writemask)) {
+ return -1; /* Other error */
+ }
+ }
+ }
+ res = writev(fd, iov, iovcnt);
+ return (res < 0) ? -1 : res;
+}
+
+int ei_writev_fill_t(int fd, const struct iovec *iov, int iovcnt, unsigned ms)
+{
+ int i;
+ int done;
+ struct iovec *iov_base = NULL;
+ struct iovec *current_iov;
+ int current_iovcnt;
+ int sum;
+
+ for (sum = 0, i = 0; i < iovcnt; ++i) {
+ sum += iov[i].iov_len;
+ }
+ if (ms != 0U) {
+ SET_NONBLOCKING(fd);
+ }
+ current_iovcnt = iovcnt;
+ current_iov = (struct iovec *) iov;
+ done = 0;
+ for (;;) {
+ i = ei_writev_t(fd, current_iov, current_iovcnt, ms);
+ if (i <= 0) { /* ei_writev_t should always return at least 1 */
+ if (ms != 0U) {
+ SET_BLOCKING(fd);
+ }
+ if (iov_base != NULL) {
+ free(iov_base);
+ }
+ return (i);
+ }
+ done += i;
+
+ if (done < sum) {
+ if (iov_base == NULL) {
+ iov_base = malloc(sizeof(struct iovec) * iovcnt);
+ memcpy(iov_base, iov, sizeof(struct iovec) * iovcnt);
+ current_iov = iov_base;
+ }
+ while (i > 0) {
+ if (i < current_iov[0].iov_len) {
+ current_iov[0].iov_len -= i;
+ i = 0;
+ } else {
+ i -= current_iov[0].iov_len;
+ current_iov++;
+ current_iovcnt--;
+ }
+ }
+ } else {
+ break;
+ }
+ }
+ if (ms != 0U) {
+ SET_BLOCKING(fd);
+ }
+ if (iov_base != NULL) {
+ free(iov_base);
+ }
+ return (sum);
+}
+
+
+#endif
+
+int ei_connect_t(int fd, void *sinp, int sin_siz, unsigned ms)
+{
+ int res;
+ int error;
+ int s_res;
+ struct timeval tv;
+ fd_set writefds;
+ fd_set exceptfds;
+
+ if (ms == 0) {
+ res = connect(fd, sinp, sin_siz);
+ return (res < 0) ? -1 : res;
+ } else {
+ SET_NONBLOCKING(fd);
+ res = connect(fd, sinp, sin_siz);
+ error = GET_SOCKET_ERROR();
+ SET_BLOCKING(fd);
+ if (!MEANS_SOCKET_ERROR(res)) {
+ return (res < 0) ? -1 : res;
+ } else {
+ if (error != ERROR_WOULDBLOCK &&
+ error != ERROR_INPROGRESS) {
+ return -1;
+ } else {
+ tv.tv_sec = (long) (ms/1000U);
+ ms %= 1000U;
+ tv.tv_usec = (long) (ms * 1000U);
+ FD_ZERO(&writefds);
+ FD_SET(fd,&writefds);
+ FD_ZERO(&exceptfds);
+ FD_SET(fd,&exceptfds);
+ s_res = select(fd + 1, NULL, &writefds, &exceptfds, &tv);
+ switch (s_res) {
+ case 0:
+ return -2;
+ case 1:
+ if (FD_ISSET(fd, &exceptfds)) {
+ return -1;
+ } else {
+ return 0; /* Connect completed */
+ }
+ default:
+ return -1;
+ }
+ }
+ }
+ }
+}
+
+int ei_accept_t(int fd, void *addr, void *addrlen, unsigned ms)
+{
+ int res;
+ if (ms != 0) {
+ fd_set readmask;
+ struct timeval tv;
+ tv.tv_sec = (time_t) (ms / 1000U);
+ ms %= 1000U;
+ tv.tv_usec = (time_t) (ms * 1000U);
+ FD_ZERO(&readmask);
+ FD_SET(fd,&readmask);
+ switch (select(fd+1, &readmask, NULL, NULL, &tv)) {
+ case -1 :
+ return -1; /* i/o error */
+ case 0:
+ return -2; /* timeout */
+ default:
+ if (!FD_ISSET(fd, &readmask)) {
+ return -1; /* Other error */
+ }
+ }
+ }
+ res = (int) accept(fd,addr,addrlen);
+ return (res < 0) ? -1 : res;
+}
+
+
+
+static int ei_read_t(int fd, char* buf, int len, unsigned ms)
+{
+ int res;
+ if (ms != 0) {
+ fd_set readmask;
+ struct timeval tv;
+ tv.tv_sec = (time_t) (ms / 1000U);
+ ms %= 1000U;
+ tv.tv_usec = (time_t) (ms * 1000U);
+ FD_ZERO(&readmask);
+ FD_SET(fd,&readmask);
+ switch (select(fd+1, &readmask, NULL, NULL, &tv)) {
+ case -1 :
+ return -1; /* i/o error */
+ case 0:
+ return -2; /* timeout */
+ default:
+ if (!FD_ISSET(fd, &readmask)) {
+ return -1; /* Other error */
+ }
+ }
+ }
+ res = readsocket(fd, buf, len);
+ return (res < 0) ? -1 : res;
+}
+
+static int ei_write_t(int fd, const char* buf, int len, unsigned ms)
+{
+ int res;
+ if (ms != 0) {
+ fd_set writemask;
+ struct timeval tv;
+ tv.tv_sec = (time_t) (ms / 1000U);
+ ms %= 1000U;
+ tv.tv_usec = (time_t) (ms * 1000U);
+ FD_ZERO(&writemask);
+ FD_SET(fd,&writemask);
+ switch (select(fd+1, NULL, &writemask, NULL, &tv)) {
+ case -1 :
+ return -1; /* i/o error */
+ case 0:
+ return -2; /* timeout */
+ default:
+ if (!FD_ISSET(fd, &writemask)) {
+ return -1; /* Other error */
+ }
+ }
+ }
+ res = writesocket(fd, buf, len);
+ return (res < 0) ? -1 : res;
+}
+
+/*
+ * Fill buffer, return buffer length, 0 for EOF, < 0 (and sets errno)
+ * for error. */
+int ei_read_fill_t(int fd, char* buf, int len, unsigned ms)
+{
+ int i,got=0;
+
+ do {
+ i = ei_read_t(fd, buf+got, len-got, ms);
+ if (i <= 0)
+ return (i);
+ got += i;
+ } while (got < len);
+ return (len);
+
+} /* read_fill */
+
+int ei_read_fill(int fd, char* buf, int len)
+{
+ return ei_read_fill_t(fd, buf, len, 0);
+}
+
+/* write entire buffer on fd or fail (setting errno)
+ */
+int ei_write_fill_t(int fd, const char *buf, int len, unsigned ms)
+{
+ int i,done=0;
+ if (ms != 0U) {
+ SET_NONBLOCKING(fd);
+ }
+ do {
+ i = ei_write_t(fd, buf+done, len-done, ms);
+ if (i <= 0) {
+ if (ms != 0U) {
+ SET_BLOCKING(fd);
+ }
+ return (i);
+ }
+ done += i;
+ } while (done < len);
+ if (ms != 0U) {
+ SET_BLOCKING(fd);
+ }
+ return (len);
+}
+
+int ei_write_fill(int fd, const char *buf, int len)
+{
+ return ei_write_fill_t(fd, buf, len, 0);
+}
+
diff --git a/lib/erl_interface/src/misc/ei_portio.h b/lib/erl_interface/src/misc/ei_portio.h
new file mode 100644
index 0000000000..f2c92278db
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_portio.h
@@ -0,0 +1,35 @@
+/*
+ * %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%
+ *
+
+ */
+#ifndef _EI_PORTIO_H
+#define _EI_PORTIO_H
+
+int ei_accept_t(int fd, void *addr, void *addrlen, unsigned ms);
+int ei_connect_t(int fd, void *sinp, int sin_siz, unsigned ms);
+int ei_read_fill(int fd, char* buf, int len);
+int ei_write_fill(int fd, const char *buf, int len);
+int ei_read_fill_t(int fd, char* buf, int len, unsigned ms);
+int ei_write_fill_t(int fd, const char *buf, int len, unsigned ms);
+#ifdef HAVE_WRITEV
+int ei_writev_fill_t(int fd, const struct iovec *iov, int iovcnt,
+ unsigned ms);
+#endif
+
+#endif /* _EI_PORTIO_H */
diff --git a/lib/erl_interface/src/misc/ei_printterm.c b/lib/erl_interface/src/misc/ei_printterm.c
new file mode 100644
index 0000000000..8d0eef5e79
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_printterm.c
@@ -0,0 +1,342 @@
+/*
+ * %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%
+ *
+
+ */
+/*
+ * Function:
+ * ei_print_term to print out a binary coded term
+ */
+
+#ifdef VXWORKS
+#include <vxWorks.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef VRTX
+#define __READY_EXTENSIONS__
+#include <errno.h>
+#endif
+
+#include "eidef.h"
+#include "eiext.h"
+#include "ei_printterm.h"
+#include "ei_malloc.h"
+
+#define BINPRINTSIZE 30
+
+/*
+ * PRINT out a binary term (hacked from 'erl'_print_term)
+ */
+
+static int print_string(FILE* fp, ei_x_buff* x, char* s, int len);
+static int print_term(FILE* fp, ei_x_buff* x,
+ const char* buf, int* index);
+
+static void xputc(char c, FILE* fp, ei_x_buff* x)
+{
+ if (fp != NULL)
+ putc(c, fp);
+ else
+ ei_x_append_buf(x, &c, 1);
+}
+
+static void xputs(const char* s, FILE* fp, ei_x_buff* x)
+{
+ if (fp != NULL)
+ fputs(s, fp);
+ else
+ ei_x_append_buf(x, s, strlen(s));
+}
+
+static int xprintf(FILE* fp, ei_x_buff* x, const char* fmt, ...)
+{
+ int r = 0;
+ va_list ap;
+ va_start(ap, fmt);
+ if (fp != NULL) {
+ r = vfprintf(fp, fmt, ap);
+ } else {
+ /* FIXME always enough in buffer??? */
+ char tmpbuf[2000];
+ r = vsprintf(tmpbuf, fmt, ap);
+ ei_x_append_buf(x, tmpbuf, strlen(tmpbuf));
+ }
+ va_end(ap);
+ return r;
+}
+
+static char *ei_big_to_str(erlang_big *b)
+{
+ int buf_len;
+ char *s,*buf;
+ unsigned short *sp;
+ int i;
+
+ buf_len = 64+b->is_neg+10*b->arity;
+ if ( (buf=malloc(buf_len)) == NULL) return NULL;
+
+ memset(buf,(char)0,buf_len);
+
+ s = buf;
+ if ( b->is_neg )
+ s += sprintf(s,"-");
+ s += sprintf(s,"#integer(%d) = {",b->arity);
+ for(sp=b->digits,i=0;i<b->arity;i++) {
+ s += sprintf(s,"%d",sp[i]);
+ if ( (i+1) != b->arity )
+ s += sprintf(s,",");
+ }
+ s += sprintf(s,"}");
+ return buf;
+}
+
+static int print_term(FILE* fp, ei_x_buff* x,
+ const char* buf, int* index)
+{
+ int i, doquote, n, m, ty, r;
+ char a[MAXATOMLEN+1], *p;
+ int ch_written = 0; /* counter of written chars */
+ erlang_pid pid;
+ erlang_port port;
+ erlang_ref ref;
+ double d;
+ long l;
+
+ int tindex = *index;
+
+ /* use temporary index for multiple (and failable) decodes */
+
+ if (fp == NULL && x == NULL) return -1;
+
+ doquote = 0;
+ ei_get_type_internal(buf, index, &ty, &n);
+ switch (ty) {
+ case ERL_ATOM_EXT:
+ if (ei_decode_atom(buf, index, a) < 0)
+ goto err;
+ doquote = !islower((int)a[0]);
+ for (p = a; !doquote && *p != '\0'; ++p)
+ doquote = !(isalnum((int)*p) || *p == '_' || *p == '@');
+ if (doquote) {
+ xputc('\'', fp, x); ++ch_written;
+ }
+ xputs(a, fp, x); ch_written += strlen(a);
+ if (doquote) {
+ xputc('\'', fp, x); ++ch_written;
+ }
+ break;
+ case ERL_PID_EXT:
+ if (ei_decode_pid(buf, index, &pid) < 0) goto err;
+ ch_written += xprintf(fp, x, "<%s.%d.%d>", pid.node,
+ pid.num, pid.serial);
+ break;
+ case ERL_PORT_EXT:
+ if (ei_decode_port(buf, index, &port) < 0) goto err;
+ ch_written += xprintf(fp, x, "#Port<%d.%d>", port.id, port.creation);
+ break;
+ case ERL_NEW_REFERENCE_EXT:
+ case ERL_REFERENCE_EXT:
+ if (ei_decode_ref(buf, index, &ref) < 0) goto err;
+ ch_written += xprintf(fp, x, "#Ref<");
+ for (i = 0; i < ref.len; ++i) {
+ ch_written += xprintf(fp, x, "%d", ref.n[i]);
+ if (i < ref.len - 1) {
+ xputc('.', fp, x); ++ch_written;
+ }
+ }
+ xputc('>', fp, x); ++ch_written;
+ break;
+ case ERL_NIL_EXT:
+ if (ei_decode_list_header(buf, index, &n) < 0) goto err;
+ ch_written += xprintf(fp, x, "[]");
+ break;
+ case ERL_LIST_EXT:
+ if (ei_decode_list_header(buf, &tindex, &n) < 0) goto err;
+ xputc('[', fp, x); ch_written++;
+ for (i = 0; i < n; ++i) {
+ r = print_term(fp, x, buf, &tindex);
+ if (r < 0) goto err;
+ ch_written += r;
+ if (i < n - 1) {
+ xputs(", ", fp, x); ch_written += 2;
+ }
+ }
+ if (ei_get_type_internal(buf, &tindex, &ty, &n) < 0) goto err;
+ if (ty != ERL_NIL_EXT) {
+ xputs(" | ", fp, x); ch_written += 3;
+ r = print_term(fp, x, buf, &tindex);
+ if (r < 0) goto err;
+ ch_written += r;
+ } else {
+ if (ei_decode_list_header(buf, &tindex, &n) < 0) goto err;
+ }
+ xputc(']', fp, x); ch_written++;
+ *index = tindex;
+ break;
+ case ERL_STRING_EXT:
+ p = ei_malloc(n+1);
+ if (p == NULL) goto err;
+ if (ei_decode_string(buf, index, p) < 0) {
+ ei_free(p);
+ goto err;
+ }
+ ch_written += print_string(fp, x, p, n);
+ ei_free(p);
+ break;
+ case ERL_SMALL_TUPLE_EXT:
+ case ERL_LARGE_TUPLE_EXT:
+ if (ei_decode_tuple_header(buf, &tindex, &n) < 0) goto err;
+ xputc('{', fp, x); ch_written++;
+
+ for (i = 0; i < n; ++i) {
+ r = print_term(fp, x, buf, &tindex);
+ if (r < 0) goto err;
+ ch_written += r;
+ if (i < n-1) {
+ xputs(", ", fp, x); ch_written += 2;
+ }
+ }
+ *index = tindex;
+ xputc('}', fp, x); ch_written++;
+ break;
+ case ERL_BINARY_EXT:
+ p = ei_malloc(n);
+ if (p == NULL) goto err;
+ if (ei_decode_binary(buf, index, p, &l) < 0) {
+ ei_free(p);
+ goto err;
+ }
+ ch_written += xprintf(fp, x, "#Bin<");
+ if (l > BINPRINTSIZE)
+ m = BINPRINTSIZE;
+ else
+ m = l;
+ --m;
+ for (i = 0; i < m; ++i) {
+ ch_written += xprintf(fp, x, "%d,", p[i]);
+ }
+ ch_written += xprintf(fp, x, "%d", p[i]);
+ if (l > BINPRINTSIZE)
+ ch_written += xprintf(fp, x, ",...");
+ xputc('>', fp, x); ++ch_written;
+ ei_free(p);
+ break;
+ case ERL_SMALL_INTEGER_EXT:
+ case ERL_INTEGER_EXT:
+ if (ei_decode_long(buf, index, &l) < 0) goto err;
+ ch_written += xprintf(fp, x, "%ld", l);
+ break;
+ case ERL_SMALL_BIG_EXT:
+ case ERL_LARGE_BIG_EXT:
+ {
+ erlang_big *b;
+ char *ds;
+
+ b = ei_alloc_big(n);
+ if (ei_decode_big(buf, index, b) < 0) {
+ ei_free_big(b);
+ goto err;
+ }
+
+ if ( (ds = ei_big_to_str(b)) == NULL ) {
+ ei_free_big(b);
+ goto err;
+ }
+
+ ch_written += xprintf(fp, x, ds);
+ free(ds);
+ ei_free_big(b);
+
+ }
+ break;
+
+ case ERL_FLOAT_EXT:
+ if (ei_decode_double(buf, index, &d) < 0) goto err;
+ ch_written += xprintf(fp, x, "%f", d);
+ break;
+ default:
+ goto err;
+ }
+ return ch_written;
+ err:
+ return -1;
+}
+
+static int print_string(FILE* fp, ei_x_buff* x, char* s, int len)
+{
+ int ch_written = 0; /* counter of written chars */
+
+ xputc('"', fp, x);
+ ++ch_written;
+ for (; len > 0; ++s, --len) {
+ int c = *s;
+ if (c >= ' ') {
+ xputc((char)c, fp, x); ++ch_written; }
+ else {
+ switch (c) {
+ case '\n': xputs("\\n", fp, x); ch_written += 2; break;
+ case '\r': xputs("\\r", fp, x); ch_written += 2; break;
+ case '\t': xputs("\\t", fp, x); ch_written += 2; break;
+ case '\v': xputs("\\v", fp, x); ch_written += 2; break;
+ case '\b': xputs("\\b", fp, x); ch_written += 2; break;
+ case '\f': xputs("\\f", fp, x); ch_written += 2; break;
+ break;
+ default:
+ ch_written += xprintf(fp, x, "\\x%x", c);
+ break;
+ }
+ }
+ }
+ xputc('"', fp, x); ch_written++;
+ return ch_written;
+}
+
+/* ------------------------------------------ */
+
+/*
+ * skip a binary term
+ */
+
+
+int ei_print_term(FILE *fp, const char* buf, int* index)
+{
+ return print_term(fp, NULL, buf, index);
+}
+
+int ei_s_print_term(char** s, const char* buf, int* index)
+{
+ int r;
+ ei_x_buff x;
+ if (*s != NULL) {
+ x.buff = *s;
+ x.index = 0;
+ x.buffsz = BUFSIZ;
+ } else {
+ ei_x_new(&x);
+ }
+ r = print_term(NULL, &x, buf, index);
+ ei_x_append_buf(&x, "", 1); /* append '\0' */
+ *s = x.buff;
+ return r;
+}
diff --git a/lib/erl_interface/src/misc/ei_printterm.h b/lib/erl_interface/src/misc/ei_printterm.h
new file mode 100644
index 0000000000..13350e3ecd
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_printterm.h
@@ -0,0 +1,24 @@
+/*
+ * %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%
+ *
+
+ */
+#ifndef _EI_PRINTTERM_H
+#define _EI_PRINTTERM_H
+
+#endif /* _EI_PRINTTERM_H */
diff --git a/lib/erl_interface/src/misc/ei_pthreads.c b/lib/erl_interface/src/misc/ei_pthreads.c
new file mode 100644
index 0000000000..a741dfd5c2
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_pthreads.c
@@ -0,0 +1,226 @@
+/*
+ * %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%
+ *
+
+ */
+
+/* FIXME why not use ei_malloc here? */
+
+#include "eidef.h"
+
+#include <stdlib.h>
+#include "ei.h"
+#include "ei_locking.h"
+
+#ifdef __WIN32__
+#ifdef USE_DECLSPEC_THREAD
+/* Define (and initialize) the variable __erl_errno */
+volatile __declspec(thread) int __erl_errno = 0;
+#else
+static volatile DWORD errno_tls_index = TLS_OUT_OF_INDEXES;
+static LONG volatile tls_init_mutex = 0;
+#endif
+#endif
+
+#if defined(VXWORKS)
+
+/*
+ Moved to each of the erl_*threads.c files, as they seem to know how
+ to get thread-safety.
+*/
+static volatile int __erl_errno;
+volatile int *__erl_errno_place(void)
+{
+ /* This check is somewhat insufficient, double task var entries will occur
+ if __erl_errno is actually -1, which on the other hand is an invalid
+ error code. */
+ if (taskVarGet(taskIdSelf(), &__erl_errno) == ERROR) {
+ taskVarAdd(taskIdSelf(), &__erl_errno);
+ }
+ return &__erl_errno;
+}
+#endif /* VXWORKS */
+
+#if defined(__WIN32__)
+
+#ifdef USE_DECLSPEC_THREAD
+
+volatile int *__erl_errno_place(void)
+{
+ return &__erl_errno;
+}
+
+#else
+static void tls_init_once(void)
+{
+
+ if (errno_tls_index != TLS_OUT_OF_INDEXES) {
+ return;
+ }
+ if (InterlockedExchange((LPLONG) &tls_init_mutex,1L) == 0) {
+ /* I was first */
+ errno_tls_index = TlsAlloc();
+ if (errno_tls_index == TLS_OUT_OF_INDEXES) {
+ fprintf(stderr,
+ "FATAL ERROR: can not allocate TLS index for "
+ "erl_errno (error code = %d)!\n",GetLastError());
+ exit(1);
+ }
+ } else {
+ while (errno_tls_index == TLS_OUT_OF_INDEXES) {
+ SwitchToThread();
+ }
+ }
+}
+
+volatile int *__erl_errno_place(void)
+{
+ volatile int *ptr;
+ tls_init_once();
+ ptr = TlsGetValue(errno_tls_index);
+ if (ptr == NULL) {
+ ptr = malloc(sizeof(int));
+ *ptr = 0;
+ TlsSetValue(errno_tls_index, (PVOID) ptr);
+ }
+ return ptr;
+}
+
+#endif /* USE_DECLSPEC_THREAD */
+
+#endif /* __WIN32__ */
+
+#if defined(_REENTRANT) && !defined(VXWORKS) && !defined(__WIN32__)
+
+#if defined(HAVE_PTHREAD_H) || defined(HAVE_MIT_PTHREAD_H)
+
+void *ei_m_create(void)
+{
+ pthread_mutex_t *l;
+
+ if ((l = malloc(sizeof(*l)))) { /* FIXME get memory or abort */
+ pthread_mutex_init(l,NULL);
+ }
+
+ return l;
+}
+
+int ei_m_destroy(void *l)
+{
+ int r = pthread_mutex_destroy(l);
+ free(l);
+
+ return r;
+}
+
+int ei_m_lock(void *l)
+{
+ return pthread_mutex_lock(l);
+}
+
+int ei_m_trylock(void *l)
+{
+ return pthread_mutex_trylock(l);
+}
+
+int ei_m_unlock(void *l)
+{
+ return pthread_mutex_unlock(l);
+}
+
+
+/*
+ * Thread-specific erl_errno variable.
+ *
+ * The second line below will give a "missing braces around initializer"
+ * on Solaris but the code will work.
+ */
+
+static pthread_key_t erl_errno_key;
+static pthread_once_t erl_errno_key_once = PTHREAD_ONCE_INIT;
+
+/*
+ * Destroy per-thread erl_errno locus
+ */
+static void erl_errno_destroy(void * ptr)
+{
+ free(ptr);
+}
+
+/*
+ * Allocate erl_errno key.
+ * This will be done once for all threads
+ */
+static void erl_errno_key_alloc(void)
+{
+ pthread_key_create(&erl_errno_key, erl_errno_destroy);
+}
+
+/*
+ * Return a pointer to the erl_errno locus.
+ * If pthread functions fail we fall back to using fallback_errno
+ * so that the main thread (actually not a thread in all ascpects)
+ * still will set and get an erl_errno value.
+ * Actually this is a bit to nice, it would be preferrable to exit fatal
+ * as we do on windows, but we might break some code with one thread
+ * but still compiled with -D_REENTRANT, so we'll leave it here.
+ */
+volatile int *__erl_errno_place(void)
+{
+ int *erl_errno_p;
+ static volatile int use_fallback = 0;
+ static volatile int fallback_errno = 0;
+
+ if (use_fallback) {
+ return &fallback_errno;
+ }
+
+ /* This will create the key once for all threads */
+ if (pthread_once(&erl_errno_key_once, erl_errno_key_alloc) != 0) {
+ use_fallback = 1;
+ return &fallback_errno;
+ }
+
+ /* This is the normal case, return the pointer to the data */
+ if ((erl_errno_p = pthread_getspecific(erl_errno_key)) != NULL) {
+ return erl_errno_p;
+ }
+
+ if ((erl_errno_p = malloc(sizeof(int))) == NULL) {
+ use_fallback = 1;
+ return &fallback_errno;
+ }
+
+ if (pthread_setspecific(erl_errno_key, erl_errno_p) != 0 ||
+ (erl_errno_p = pthread_getspecific(erl_errno_key)) == NULL) {
+ free(erl_errno_p);
+ return &fallback_errno;
+ }
+
+ return erl_errno_p;
+}
+
+#endif /* HAVE_PTHREAD_H || HAVE_MIT_PTHREAD_H */
+
+#endif /* _REENTRANT && !VXWORKS && !__WIN32__ */
+
+#if !defined(_REENTRANT) && !defined(VXWORKS) && !defined(__WIN32__)
+
+volatile int __erl_errno;
+
+#endif
diff --git a/lib/erl_interface/src/misc/ei_trace.c b/lib/erl_interface/src/misc/ei_trace.c
new file mode 100644
index 0000000000..fb183c8be4
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_trace.c
@@ -0,0 +1,56 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include "eidef.h"
+#include "ei_trace.h"
+
+/* this is our lamport clock */
+erlang_trace *ei_trace(int query, erlang_trace *token)
+{
+ /* FIXME problem for threaded ? */
+ static erlang_trace save_token;
+ static int tracing = 0;
+ static int clock = 0;
+
+
+ switch (query) {
+ case -1: /* we are no longer tracing */
+ tracing = 0;
+ break;
+
+ case 0: /* are we tracing? */
+ if (tracing) {
+ clock++;
+ save_token.prev = save_token.serial++;
+ return &save_token;
+ }
+ break;
+
+ case 1: /* we are now tracing */
+ tracing = 1;
+ save_token = *token;
+ if (save_token.serial > clock)
+ save_token.prev = clock = token->serial;
+ break;
+ }
+
+ return NULL;
+}
+
diff --git a/lib/erl_interface/src/misc/ei_trace.h b/lib/erl_interface/src/misc/ei_trace.h
new file mode 100644
index 0000000000..d3513c9353
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_trace.h
@@ -0,0 +1,26 @@
+/*
+ * %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%
+ *
+
+ */
+#ifndef _EI_TRACE_H
+#define _EI_TRACE_H
+
+erlang_trace *ei_trace(int query, erlang_trace *token);
+
+#endif /* _EI_TRACE_H */
diff --git a/lib/erl_interface/src/misc/ei_x_encode.c b/lib/erl_interface/src/misc/ei_x_encode.c
new file mode 100644
index 0000000000..fa1e26ccbb
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_x_encode.c
@@ -0,0 +1,255 @@
+/*
+ * %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%
+ *
+
+ */
+/*
+ * ei_x_encode to encode in a self-expanding buffer
+ */
+
+#ifdef VXWORKS
+#include <vxWorks.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef VRTX
+#define __READY_EXTENSIONS__
+#include <errno.h>
+#endif
+
+#include "eidef.h"
+#include "ei_x_encode.h"
+#include "ei_malloc.h"
+
+int ei_x_extra = 100;
+
+int ei_x_new(ei_x_buff* x)
+{
+ x->buff = ei_malloc(ei_x_extra);
+ x->buffsz = ei_x_extra;
+ x->index = 0;
+ return x->buff != NULL ? 0 : -1;
+}
+
+int ei_x_new_with_version(ei_x_buff* x)
+{
+ if (ei_x_new(x) < 0)
+ return -1;
+ return ei_encode_version(x->buff, &x->index);
+}
+
+int ei_x_free(ei_x_buff* x)
+{
+ if (x->buff == NULL)
+ return -1;
+ ei_free(x->buff);
+ x->buff = NULL;
+ return 0;
+}
+
+int x_fix_buff(ei_x_buff* x, int szneeded)
+{
+ int sz = szneeded + ei_x_extra;
+ if (sz > x->buffsz) {
+ sz += ei_x_extra; /* to avoid reallocating each and every time */
+ x->buffsz = sz;
+ x->buff = ei_realloc(x->buff, sz);
+ }
+ return x->buff != NULL;
+}
+
+int ei_x_append(ei_x_buff* x, const ei_x_buff* x2)
+{
+ return ei_x_append_buf(x, x2->buff, x2->index);
+}
+
+int ei_x_append_buf(ei_x_buff* x, const char* buf, int len)
+{
+ if (!x_fix_buff(x, x->index+len))
+ return -1;
+ memcpy(&x->buff[x->index], buf, len);
+ x->index += len;
+ return 0;
+}
+
+int ei_x_encode_string(ei_x_buff* x, const char* s)
+{
+ return ei_x_encode_string_len(x, s, strlen(s));
+}
+
+int ei_x_encode_string_len(ei_x_buff* x, const char* s, int len)
+{
+ int i = x->index;
+ ei_encode_string_len(NULL, &i, s, len);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_string_len(x->buff, &x->index, s, len);
+}
+
+int ei_x_encode_binary(ei_x_buff* x, const void* p, int len)
+{
+ int i = x->index;
+ ei_encode_binary(NULL, &i, p, len);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_binary(x->buff, &x->index, p, len);
+}
+
+int ei_x_encode_long(ei_x_buff* x, long n)
+{
+ int i = x->index;
+ ei_encode_long(NULL, &i, n);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_long(x->buff, &x->index, n);
+}
+
+int ei_x_encode_ulong(ei_x_buff* x, unsigned long n)
+{
+ int i = x->index;
+ ei_encode_ulong(NULL, &i, n);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_ulong(x->buff, &x->index, n);
+}
+
+int ei_x_encode_char(ei_x_buff* x, char p)
+{
+ int i = x->index;
+ ei_encode_char(NULL, &i, p);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_char(x->buff, &x->index, p);
+}
+
+int ei_x_encode_boolean(ei_x_buff* x, int p)
+{
+ int i = x->index;
+ ei_encode_boolean(NULL, &i, p);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_boolean(x->buff, &x->index, p);
+}
+
+int ei_x_encode_double(ei_x_buff* x, double dbl)
+{
+ int i = x->index;
+ ei_encode_double(NULL, &i, dbl);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_double(x->buff, &x->index, dbl);
+}
+
+int ei_x_encode_list_header(ei_x_buff* x, long n)
+{
+ int i = x->index;
+ ei_encode_list_header(NULL, &i, n);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_list_header(x->buff, &x->index, n);
+}
+
+int ei_x_encode_empty_list(ei_x_buff* x)
+{
+ int i = x->index;
+ ei_encode_empty_list(NULL, &i);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_empty_list(x->buff, &x->index);
+}
+
+int ei_x_encode_version(ei_x_buff* x)
+{
+ int i = x->index;
+ ei_encode_version(NULL, &i);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_version(x->buff, &x->index);
+}
+
+int ei_x_encode_tuple_header(ei_x_buff* x, long n)
+{
+ int i = x->index;
+ ei_encode_tuple_header(NULL, &i, n);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_tuple_header(x->buff, &x->index, n);
+}
+
+int ei_x_encode_atom(ei_x_buff* x, const char* s)
+{
+ return ei_x_encode_atom_len(x, s, strlen(s));
+}
+
+int ei_x_encode_atom_len(ei_x_buff* x, const char* s, int len)
+{
+ int i = x->index;
+ ei_encode_atom_len(NULL, &i, s, len);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_atom_len(x->buff, &x->index, s, len);
+}
+
+int ei_x_encode_pid(ei_x_buff* x, const erlang_pid* pid)
+{
+ int i = x->index;
+ ei_encode_pid(NULL, &i, pid);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_pid(x->buff, &x->index, pid);
+}
+
+int ei_x_encode_fun(ei_x_buff* x, const erlang_fun* fun)
+{
+ int i = x->index;
+ ei_encode_fun(NULL, &i, fun);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_fun(x->buff, &x->index, fun);
+}
+
+int ei_x_encode_ref(ei_x_buff* x, const erlang_ref* ref)
+{
+ int i = x->index;
+ ei_encode_ref(NULL, &i, ref);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_ref(x->buff, &x->index, ref);
+}
+
+int ei_x_encode_port(ei_x_buff* x, const erlang_port* port)
+{
+ int i = x->index;
+ ei_encode_port(NULL, &i, port);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_port(x->buff, &x->index, port);
+}
+
+int ei_x_encode_trace(ei_x_buff* x, const erlang_trace* trace)
+{
+ int i = x->index;
+ ei_encode_trace(NULL, &i, trace);
+ if (!x_fix_buff(x, i))
+ return -1;
+ return ei_encode_trace(x->buff, &x->index, trace);
+}
diff --git a/lib/erl_interface/src/misc/ei_x_encode.h b/lib/erl_interface/src/misc/ei_x_encode.h
new file mode 100644
index 0000000000..3eab23ce0a
--- /dev/null
+++ b/lib/erl_interface/src/misc/ei_x_encode.h
@@ -0,0 +1,31 @@
+/*
+ * %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%
+ *
+
+ */
+/*
+ * Function:
+ * ei_x_encode to encode in a self-expanding buffer
+ */
+
+#ifndef _EI_X_ENCODE_H
+#define _EI_X_ENCODE_H
+
+int x_fix_buff(ei_x_buff* x, int szneeded);
+
+#endif /* _EI_X_ENCODE_H */
diff --git a/lib/erl_interface/src/misc/eidef.h b/lib/erl_interface/src/misc/eidef.h
new file mode 100644
index 0000000000..bd3d0bf631
--- /dev/null
+++ b/lib/erl_interface/src/misc/eidef.h
@@ -0,0 +1,51 @@
+/*
+ * %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%
+ *
+
+ */
+
+#ifndef _EIDEF_H
+#define _EIDEF_H
+
+/* Common definitions used in ei user interface */
+
+#include "config.h" /* Central include of config.h */
+
+/* vxWorks.h needs to be before stddef.h */
+#ifdef VXWORKS
+#include <vxWorks.h>
+#endif
+
+#include <stddef.h> /* We want to get definition of NULL */
+
+#include "ei.h" /* Want the API function declarations */
+
+#define EISMALLBUF 2048
+
+#ifndef HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif
+
+typedef unsigned char uint8; /* FIXME use configure */
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+typedef signed char int8;
+typedef signed short int16;
+typedef signed int int32;
+
+#endif /* _EIDEF_H */
diff --git a/lib/erl_interface/src/misc/eiext.h b/lib/erl_interface/src/misc/eiext.h
new file mode 100644
index 0000000000..85ed9e0d50
--- /dev/null
+++ b/lib/erl_interface/src/misc/eiext.h
@@ -0,0 +1,35 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ *
+
+ */
+#ifndef _EIEXT_H
+#define _EIEXT_H
+
+/* FIXME maybe put into eidef.h */
+
+#define ERL_VERSION_MAGIC 131 /* 130 in erlang 4.2 */
+
+/* from erl_eterm.h */
+#define ERL_MAX ((1 << 27)-1)
+#define ERL_MIN -(1 << 27)
+
+/* FIXME we removed lots of defines, maybe some C files don't need to include
+ this header any longer? */
+
+#endif /* _EIEXT_H */
diff --git a/lib/erl_interface/src/misc/eimd5.c b/lib/erl_interface/src/misc/eimd5.c
new file mode 100644
index 0000000000..426b96d962
--- /dev/null
+++ b/lib/erl_interface/src/misc/eimd5.c
@@ -0,0 +1,319 @@
+/*
+ * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+#include "eidef.h"
+
+#include <string.h>
+#include "eimd5.h"
+
+/*
+ * Constants for MD5Transform routine.
+ */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform(UINT4 [4], unsigned char [64]);
+static void Encode(unsigned char *, UINT4 *, unsigned int);
+static void Decode(UINT4 *, unsigned char *, unsigned int);
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/*
+ * ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/*
+ * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+ * Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+}
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+}
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+}
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+}
+
+
+/*
+ * MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void ei_MD5Init(MD5_CTX* context)
+{
+ context->count[0] = context->count[1] = 0;
+
+ /*
+ * Load magic initialization constants.
+ */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/*
+ * MD5 block update operation. Continues an MD5 message-digest
+ * operation, processing another message block, and updating the
+ * context.
+ */
+void ei_MD5Update (MD5_CTX *context, unsigned char *input,
+ unsigned int inputLen)
+{
+ unsigned int i, index, partLen;
+
+ /*
+ * Compute number of bytes mod 64
+ */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /*
+ * Transform as many times as possible.
+ */
+ if (inputLen >= partLen) {
+ memcpy
+ ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /*
+ * Buffer remaining input
+ */
+ memcpy((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
+}
+
+/*
+ * MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void ei_MD5Final (unsigned char digest[16], MD5_CTX *context)
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /*
+ * Save number of bits
+ */
+ Encode (bits, context->count, 8);
+
+ /*
+ * Pad out to 56 mod 64.
+ */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ ei_MD5Update (context, PADDING, padLen);
+
+ /*
+ * Append length (before padding)
+ */
+ ei_MD5Update (context, bits, 8);
+
+ /*
+ * Store state in digest
+ */
+ Encode (digest, context->state, 16);
+
+ /*
+ * Zeroize sensitive information.
+ */
+ memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/*
+ * MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (UINT4 state[4], unsigned char block[64])
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /*
+ * Zeroize sensitive information.
+ */
+ memset ((POINTER)x, 0, sizeof (x));
+}
+
+/*
+ * Encodes input (UINT4) into output (unsigned char). Assumes len is
+ * a multiple of 4.
+ */
+static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/*
+ * Decodes input (unsigned char) into output (UINT4). Assumes len is
+ * a multiple of 4.
+ */
+static void Decode (UINT4 *output, unsigned char *input, unsigned int len)
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
diff --git a/lib/erl_interface/src/misc/eimd5.h b/lib/erl_interface/src/misc/eimd5.h
new file mode 100644
index 0000000000..746f06e236
--- /dev/null
+++ b/lib/erl_interface/src/misc/eimd5.h
@@ -0,0 +1,48 @@
+/*
+ * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+#ifndef _EIMD5_H
+#define _EIMD5_H
+
+typedef unsigned UINT4; /* Should be 32 bits. */
+typedef void *POINTER;
+
+
+/*
+ * MD5 context.
+ */
+
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+void ei_MD5Init(MD5_CTX *);
+void ei_MD5Update(MD5_CTX *, unsigned char *, unsigned int);
+void ei_MD5Final(unsigned char [16], MD5_CTX *);
+
+#endif /* _EIMD5_H */
diff --git a/lib/erl_interface/src/misc/get_type.c b/lib/erl_interface/src/misc/get_type.c
new file mode 100644
index 0000000000..d67a6a80d3
--- /dev/null
+++ b/lib/erl_interface/src/misc/get_type.c
@@ -0,0 +1,149 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include "eidef.h"
+#include "eiext.h"
+#include "putget.h"
+
+/* report type identifier from the start of the buffer */
+/* for types with meaningful length attributes, return the length too.
+ In other cases, return length 0 */
+
+/* FIXME working on this one.... */
+
+int ei_get_type(const char *buf, const int *index, int *type, int *len)
+{
+ return ei_get_type_internal(buf, index, type, len);
+}
+
+#if 0
+int ei_get_type(const char *buf, const int *index, int *type, int *len)
+{
+ const char *s = buf + *index;
+ int itype = get8(s); /* Internal type */
+
+ *len = 0;
+
+ switch (*type) {
+
+ case ERL_SMALL_INTEGER_EXT:
+ case ERL_INTEGER_EXT:
+ case ERL_SMALL_BIG_EXT:
+ case ERL_LARGE_BIG_EXT:
+ *type = EI_TYPE_INTEGER;
+ break;
+
+ case ERL_FLOAT_EXT:
+ *type = EI_TYPE_FLOAT;
+ break;
+
+ case ERL_SMALL_TUPLE_EXT:
+ *len = get8(s);
+ break;
+
+ case ERL_ATOM_EXT:
+ case ERL_STRING_EXT:
+ *len = get16be(s);
+ break;
+
+ case ERL_LARGE_TUPLE_EXT:
+ case ERL_LIST_EXT:
+ case ERL_BINARY_EXT:
+ *len = get32be(s);
+ break;
+
+ case ERL_SMALL_BIG_EXT:
+ *len = (get8(s)+1)/2; /* big arity */
+ break;
+
+ case ERL_LARGE_BIG_EXT:
+ *len = (get32be(s)+1)/2; /* big arity */
+ break;
+
+ case ERL_BINARY_EXT:
+ *type = EI_TYPE_BINARY;
+ break;
+
+ case ERL_PID_EXT:
+ *type = EI_TYPE_PID;
+ break;
+
+ case ERL_PORT_EXT:
+ *type = EI_TYPE_PORT;
+ break;
+
+ case ERL_REFERENCE_EXT:
+ case ERL_NEW_REFERENCE_EXT:
+ *type = EI_TYPE_REF;
+ break;
+
+ default:
+ break;
+ }
+
+ /* leave index unchanged */
+ return 0;
+}
+#endif
+
+
+/* Old definition of function above */
+
+int ei_get_type_internal(const char *buf, const int *index,
+ int *type, int *len)
+{
+ const char *s = buf + *index;
+
+ *type = get8(s);
+
+ switch (*type) {
+ case ERL_SMALL_TUPLE_EXT:
+ *len = get8(s);
+ break;
+
+ case ERL_ATOM_EXT:
+ case ERL_STRING_EXT:
+ *len = get16be(s);
+ break;
+
+ case ERL_LARGE_TUPLE_EXT:
+ case ERL_LIST_EXT:
+ case ERL_BINARY_EXT:
+ *len = get32be(s);
+ break;
+
+ case ERL_SMALL_BIG_EXT:
+ *len = get8(s); /* #digit_bytes */
+ break;
+
+ case ERL_LARGE_BIG_EXT:
+ *len = get32be(s); /* #digit_bytes */
+ break;
+
+ default:
+ *len = 0;
+ break;
+ }
+
+ /* leave index unchanged */
+ return 0;
+}
+
+
diff --git a/lib/erl_interface/src/misc/putget.h b/lib/erl_interface/src/misc/putget.h
new file mode 100644
index 0000000000..98d9ebb64c
--- /dev/null
+++ b/lib/erl_interface/src/misc/putget.h
@@ -0,0 +1,85 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ *
+
+ */
+#ifndef _PUTGET_H
+#define _PUTGET_H
+
+#define put8(s,n) do { \
+ (s)[0] = (char)((n) & 0xff); \
+ (s) += 1; \
+} while (0)
+
+#define put16le(s,n) do { \
+ (s)[0] = (n) & 0xff; \
+ (s)[1] = ((n) >> 8) & 0xff; \
+ (s) += 2; \
+} while (0) \
+
+#define put32le(s,n) do { \
+ (s)[0] = (n) & 0xff; \
+ (s)[1] = ((n) >> 8) & 0xff; \
+ (s)[2] = ((n) >> 16) & 0xff; \
+ (s)[3] = ((n) >> 24) & 0xff; \
+ (s) += 4; \
+} while (0)
+
+#define put16be(s,n) do { \
+ (s)[0] = ((n) >> 8) & 0xff; \
+ (s)[1] = (n) & 0xff; \
+ (s) += 2; \
+} while (0)
+
+#define put32be(s,n) do { \
+ (s)[0] = ((n) >> 24) & 0xff; \
+ (s)[1] = ((n) >> 16) & 0xff; \
+ (s)[2] = ((n) >> 8) & 0xff; \
+ (s)[3] = (n) & 0xff; \
+ (s) += 4; \
+} while (0)
+
+#define get8(s) \
+ ((s) += 1, \
+ ((unsigned char *)(s))[-1] & 0xff)
+
+#define get16le(s) \
+ ((s) += 2, \
+ (((((unsigned char *)(s))[-1] << 8) | \
+ ((unsigned char *)(s))[-2])) & 0xffff)
+
+#define get32le(s) \
+ ((s) += 4, \
+ ((((unsigned char *)(s))[-1] << 24) | \
+ (((unsigned char *)(s))[-2] << 16) | \
+ (((unsigned char *)(s))[-3] << 8) | \
+ ((unsigned char *)(s))[-4]))
+
+#define get16be(s) \
+ ((s) += 2, \
+ (((((unsigned char *)(s))[-2] << 8) | \
+ ((unsigned char *)(s))[-1])) & 0xffff)
+
+#define get32be(s) \
+ ((s) += 4, \
+ ((((unsigned char *)(s))[-4] << 24) | \
+ (((unsigned char *)(s))[-3] << 16) | \
+ (((unsigned char *)(s))[-2] << 8) | \
+ ((unsigned char *)(s))[-1]))
+
+#endif /* _PUTGET_H */
diff --git a/lib/erl_interface/src/misc/show_msg.c b/lib/erl_interface/src/misc/show_msg.c
new file mode 100644
index 0000000000..25865d6f8e
--- /dev/null
+++ b/lib/erl_interface/src/misc/show_msg.c
@@ -0,0 +1,584 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <sys/types.h>
+
+#include "eidef.h"
+
+#ifndef __WIN32__
+# ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+# endif
+#endif
+
+#include "eiext.h"
+#include "putget.h"
+#include "ei_printterm.h"
+#include "ei_internal.h"
+#include "show_msg.h"
+
+#ifndef EISHOWBUF
+#define EISHOWBUF 512
+#endif
+
+static void show_term(const char *termbuf, int *index, FILE *stream);
+static void show_pid(FILE *stream, const erlang_pid *pid);
+static void show_trace(FILE *stream, const erlang_trace *t);
+static void show_msg(FILE *stream, int direction, const erlang_msg *msg,
+ const char *buf);
+static void ei_efprint(FILE *stream, const char *termbuf);
+static int ei_decode_skip_bignum(const char *buf, int *index, void *p);
+static int printable_list_p(const uint8 *buf, int buflen);
+
+
+/***************************************************************************
+ *
+ * Write trace information to stderr
+ *
+ ***************************************************************************/
+
+void ei_trace_printf(const char *name, int level, const char *format,...)
+{
+ time_t now;
+ char *timestr;
+ char buf[2048];
+ int len;
+ va_list args;
+
+ va_start(args, format);
+
+ time(&now);
+ timestr = (char *)ctime(&now);
+ sprintf(buf, "%s: %.*s: ", name, (int) strlen(timestr)-1, timestr);
+ len = strlen(buf);
+ vsprintf(buf + len, format, args);
+ fprintf(stderr,"%s\r\n",buf);
+ va_end(args);
+}
+
+
+/***************************************************************************
+ *
+ * Debug printing of incoming and outgoing messages
+ *
+ ***************************************************************************/
+
+/*
+ * FIXME maybe this function should be rewritten to use ei_printterm instead
+ * (or the other way around)
+ */
+
+/*
+ * the new TT stuff has been added, but when these messages are shown
+ * they will look just like the non-tt ones for now.
+ */
+
+/*
+ * this should be long enough for longest atoms (256) but short enough for
+ * fprintf to handle all at once (a few kb probably).
+ */
+
+
+void ei_show_recmsg(FILE *stream, erlang_msg *msg, char *buf)
+{
+ show_msg(stream, 0, msg, buf);
+}
+
+
+/* decode the buffer again before showing it */
+int ei_show_sendmsg(FILE *stream, const char *header, const char *msgbuf)
+{
+ erlang_msg msg;
+ const char *mbuf = NULL;
+ int index = 0;
+ int arity = 0;
+ int version = 0;
+
+ /* skip five bytes */
+ index = 5;
+ ei_decode_version(header,&index,&version);
+ ei_decode_tuple_header(header,&index,&arity);
+ ei_decode_long(header,&index,&msg.msgtype);
+
+ switch (msg.msgtype) {
+ case ERL_SEND:
+ if (ei_decode_atom(header,&index,msg.cookie)
+ || ei_decode_pid(header,&index,&msg.to)) return -1;
+ mbuf = msgbuf;
+ break;
+
+ case ERL_SEND_TT:
+ if (ei_decode_atom(header,&index,msg.cookie)
+ || ei_decode_pid(header,&index,&msg.to)
+ || ei_decode_trace(header,&index,&msg.token)) return -1;
+ mbuf = msgbuf;
+ break;
+
+ case ERL_REG_SEND:
+ if (ei_decode_pid(header,&index,&msg.from)
+ || ei_decode_atom(header,&index,msg.cookie)
+ || ei_decode_atom(header,&index,msg.toname)) return -1;
+ mbuf = msgbuf;
+ break;
+
+ case ERL_REG_SEND_TT:
+ if (ei_decode_pid(header,&index,&msg.from)
+ || ei_decode_atom(header,&index,msg.cookie)
+ || ei_decode_atom(header,&index,msg.toname)
+ || ei_decode_trace(header,&index,&msg.token)) return -1;
+ mbuf = msgbuf;
+ break;
+
+ case ERL_EXIT:
+ case ERL_EXIT2:
+ if (ei_decode_pid(header,&index,&msg.from)
+ || ei_decode_pid(header,&index,&msg.to)) return -1;
+ mbuf = header+index;
+
+ case ERL_EXIT_TT:
+ case ERL_EXIT2_TT:
+ if (ei_decode_pid(header,&index,&msg.from)
+ || ei_decode_pid(header,&index,&msg.to)
+ || ei_decode_trace(header,&index,&msg.token)) return -1;
+ mbuf = header+index;
+ break;
+
+ case ERL_LINK:
+ case ERL_UNLINK:
+ case ERL_GROUP_LEADER:
+ if (ei_decode_pid(header,&index,&msg.from)
+ || ei_decode_pid(header,&index,&msg.to)) return -1;
+ mbuf = header;
+ break;
+
+ case ERL_NODE_LINK:
+ /* nothing to do */
+ mbuf = header;
+ break;
+
+ default:
+ break;
+ }
+
+ show_msg(stream, 1, &msg, mbuf);
+
+ return 0;
+}
+
+
+/***************************************************************************
+ *
+ * Common function for ei_show_recmsg() and ei_show_sendmsg()
+ *
+ ***************************************************************************/
+
+static void show_msg(FILE *stream, int direction, const erlang_msg *msg,
+ const char *buf)
+{
+ if (direction) fprintf(stream,"-> ");
+ else fprintf(stream,"<- ");
+
+ switch (msg->msgtype) {
+ case ERL_LINK:
+ fprintf(stream,"LINK From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: ");
+ show_pid(stream,&msg->to);
+ break;
+
+ case ERL_SEND:
+ fprintf(stream,"SEND To: ");
+ show_pid(stream,&msg->to);
+ fprintf(stream,"\n ");
+ /* show the message */
+ ei_efprint(stream,buf);
+ break;
+
+ case ERL_EXIT:
+ fprintf(stream,"EXIT From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: ");
+ show_pid(stream,&msg->to);
+ /* show the reason */
+ fprintf(stream,"\n Reason: ");
+ ei_efprint(stream,buf);
+ break;
+
+ case ERL_UNLINK:
+ fprintf(stream,"UNLINK From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: ");
+ show_pid(stream,&msg->to);
+ break;
+
+ case ERL_NODE_LINK:
+ fprintf(stream,"NODE_LINK");
+ break;
+
+ case ERL_REG_SEND:
+ fprintf(stream,"REG_SEND From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: %s\n ",msg->toname);
+ /* show the message */
+ ei_efprint(stream,buf);
+ break;
+
+ case ERL_GROUP_LEADER:
+ fprintf(stream,"GROUP_LEADER From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: ");
+ show_pid(stream,&msg->to);
+ break;
+
+ case ERL_EXIT2:
+ fprintf(stream,"EXIT2 From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: ");
+ show_pid(stream,&msg->to);
+ /* show the reason */
+ fprintf(stream,"\n Reason: ");
+ ei_efprint(stream,buf);
+ break;
+
+ /* the new TT stuff below */
+
+ case ERL_EXIT_TT:
+ fprintf(stream,"EXIT_TT From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: ");
+ show_pid(stream,&msg->to);
+ fprintf(stream,"\n ");
+ show_trace(stream,&msg->token);
+ /* show the reason */
+ fprintf(stream,"\n Reason: ");
+ ei_efprint(stream,buf);
+ break;
+
+ case ERL_EXIT2_TT:
+ fprintf(stream,"EXIT2_TT From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: ");
+ show_pid(stream,&msg->to);
+ fprintf(stream,"\n ");
+ show_trace(stream,&msg->token);
+ /* show the reason */
+ fprintf(stream,"\n Reason: ");
+ ei_efprint(stream,buf);
+ break;
+
+ case ERL_SEND_TT:
+ fprintf(stream,"SEND_TT To: ");
+ show_pid(stream,&msg->to);
+ fprintf(stream,"\n ");
+ show_trace(stream,&msg->token);
+ fprintf(stream,"\n ");
+ /* show the message */
+ ei_efprint(stream,buf);
+ break;
+
+ case ERL_REG_SEND_TT:
+ fprintf(stream,"REG_SEND_TT From: ");
+ show_pid(stream,&msg->from);
+ fprintf(stream," To: %s\n ",msg->toname);
+ show_trace(stream,&msg->token);
+ fprintf(stream,"\n ");
+ /* show the message */
+ ei_efprint(stream,buf);
+ break;
+
+ default:
+ fprintf(stream,"Unknown message type: %ld",msg->msgtype);
+ }
+ fprintf(stream,"\n");
+}
+
+/***************************************************************************
+ *
+ * Print term to stream with fprintf
+ *
+ ***************************************************************************/
+
+
+static void ei_efprint(FILE *stream, const char *termbuf)
+{
+ int index = 0;
+ show_term(termbuf,&index,stream);
+}
+
+static void show_term(const char *termbuf, int *index, FILE *stream)
+{
+ int type;
+ char smallbuf[EISHOWBUF];
+ int version;
+ long num;
+ double fnum;
+ erlang_pid pid;
+ erlang_port port;
+ erlang_ref ref;
+ int i, len;
+ char *s;
+
+ ei_get_type_internal(termbuf,index,&type,&len);
+
+ switch (type) {
+ case ERL_VERSION_MAGIC:
+ /* just skip past this */
+ ei_decode_version(termbuf,index,&version);
+ show_term(termbuf,index,stream);
+ break;
+
+ case ERL_ATOM_EXT:
+ ei_decode_atom(termbuf,index,smallbuf);
+ fprintf(stream,"%s",smallbuf);
+ break;
+
+ case ERL_STRING_EXT:
+ /* strings can be much longer than EISHOWBUF */
+ if (len < EISHOWBUF) s = smallbuf;
+ else if (!(s = malloc(len+1))) break; /* FIXME just break if can't? */
+
+ ei_decode_string(termbuf,index,s);
+
+ if (printable_list_p((uint8 *)s,len)) {
+ /* just show it as it is */
+ fprintf(stream,"\"%s\"",s);
+ } else {
+ /* show it as a list instead */
+ fprintf(stream,"[");
+ for (i=0; i<len; i++) {
+ if (i > 0) fprintf(stream,", ");
+ fprintf(stream,"%d",s[i]);
+ }
+ fprintf(stream,"]");
+ }
+
+ /* did we allocate anything? */
+ if (s && (s != smallbuf)) free(s);
+
+ break;
+
+ /* FIXME add case using ei_decode_longlong */
+ case ERL_SMALL_BIG_EXT:
+ case ERL_SMALL_INTEGER_EXT:
+ case ERL_INTEGER_EXT:
+ if (ei_decode_long(termbuf,index,&num) == 0) {
+ fprintf(stream,"%ld",num);
+ } else {
+ ei_decode_skip_bignum(termbuf,index,NULL);
+ fprintf(stream,"#Bignum");
+ }
+ break;
+
+ case ERL_FLOAT_EXT:
+ ei_decode_double(termbuf,index,&fnum);
+ fprintf(stream,"%f",fnum);
+ break;
+
+ case ERL_PID_EXT:
+ ei_decode_pid(termbuf,index,&pid);
+ show_pid(stream,&pid);
+ break;
+
+ case ERL_SMALL_TUPLE_EXT:
+ case ERL_LARGE_TUPLE_EXT:
+ ei_decode_tuple_header(termbuf,index,&len);
+ fprintf(stream,"{");
+ for (i=0; i<len; i++) {
+ if (i > 0) fprintf(stream,", ");
+ show_term(termbuf,index,stream);
+ }
+ fprintf(stream,"}");
+ break;
+
+ case ERL_LIST_EXT:
+ ei_decode_list_header(termbuf,index,&len);
+ fprintf(stream,"[");
+ for (i=0; i<len; i++) {
+ if (i > 0) fprintf(stream,", ");
+ show_term(termbuf,index,stream);
+ }
+ /* get the empty list at the end */
+ ei_decode_list_header(termbuf,index,&len);
+ fprintf(stream,"]");
+ break;
+
+ case ERL_NIL_EXT:
+ ei_decode_list_header(termbuf,index,&len);
+ fprintf(stream,"[]");
+ break;
+
+ case ERL_REFERENCE_EXT:
+ case ERL_NEW_REFERENCE_EXT:
+ ei_decode_ref(termbuf,index,&ref);
+ fprintf(stream,"#Ref<%s",ref.node);
+ for (i = 0; i < ref.len; i++) {
+ fprintf(stream,".%u",ref.n[i]);
+ }
+ fprintf(stream,".%u>",ref.creation);
+ break;
+
+ case ERL_PORT_EXT:
+ ei_decode_port(termbuf,index,&port);
+ fprintf(stream,"#Port<%s.%u.%u>",port.node,port.id,port.creation);
+ break;
+
+ case ERL_BINARY_EXT:
+ ei_decode_binary(termbuf,index,NULL,&num);
+ fprintf(stream,"#Bin<%ld>",num);
+ break;
+
+ case ERL_LARGE_BIG_EXT:
+ /* doesn't actually decode - just skip over it */
+ /* FIXME if GMP, what to do here?? */
+ ei_decode_skip_bignum(termbuf,index,NULL);
+ fprintf(stream,"#Bignum");
+ break;
+
+ case ERL_FUN_EXT: {
+ char atom[MAXATOMLEN+1];
+ long idx;
+ long uniq;
+ const char* s = termbuf + *index, * s0 = s;
+ int n_free;
+
+ ++s;
+ n_free = get32be(s);
+ *index += s - s0;
+ ei_decode_pid(termbuf, index, NULL); /* skip pid */
+ ei_decode_atom(termbuf, index, atom); /* get module, index, uniq */
+ ei_decode_long(termbuf, index, &idx);
+ ei_decode_long(termbuf, index, &uniq);
+ fprintf(stream,"#Fun<%s.%ld.%ld>", atom, idx, uniq);
+ for (i = 0; i < n_free; ++i) {
+ /* FIXME how to report error ?! */
+ if (ei_skip_term(termbuf, index) != 0)
+ fprintf(stderr,"<ERROR> show_msg: unknown type of term !");
+ }
+ break;
+ }
+ default:
+ fprintf(stream,"#Unknown<%d.%d>",type,len);
+ /* unfortunately we don't know how to skip over this type in
+ * the buffer if we don't even know what it is, so we return.
+ */
+ return;
+ break;
+ }
+}
+
+/***************************************************************************
+ *
+ * this help function does the actual decoding of the
+ * terms and is used by both ei_efprint and ei_sprintt.
+ *
+ * termbuf contains the undecoded term.
+ * idx is the current position in termbuf.
+ * stream is print destination, e.g. a FILE*
+ *
+ ***************************************************************************/
+
+static void show_pid(FILE *stream, const erlang_pid *pid)
+{
+ fprintf(stream,"#Pid<%s.%u.%u.%u>",
+ pid->node,pid->num,pid->serial,pid->creation);
+}
+
+static void show_trace(FILE *stream, const erlang_trace *t)
+{
+ fprintf(stream,
+ "Trace: Label: %ld, Flags: 0x%lx serial: %ld, prev: %ld From: ",
+ t->label,t->flags,t->serial,t->prev);
+ show_pid(stream,&t->from);
+}
+
+/***************************************************************************
+ *
+ * Try do decide if a buffer only contains printable characters
+ *
+ ***************************************************************************/
+
+/* we only need to initialize some of these (after 32 everything printable) */
+/* FIXME they are not!!!! We use isprint() for now but we could create a */
+/* custom print function that escape some non printable like \t and \n */
+#if 0
+static int non_printable[256] = {
+ /* 1 2 3 */
+ /* 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 */
+ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
+ /* \b\t\n\v\f\r */
+};
+#endif
+
+static int printable_list_p(const uint8 *buf, int buflen)
+{
+ int i;
+
+ for (i=0; i<buflen; i++) if (!isprint(buf[i])) return 0;
+
+ /* is printable */
+ return 1;
+}
+
+/***************************************************************************
+ *
+ * Skip over bignums, we can't print them
+ *
+ ***************************************************************************/
+
+/* FIXME we can if bignum small enough or if we use Per's functions or
+ if we have compiled in gmp support */
+
+/* this function doesn't do anything but skip over the number in the buffer */
+/* it doesn't really belong here either... */
+
+static int ei_decode_skip_bignum(const char *buf, int *index, void *p)
+{
+ const char *s = buf + *index;
+ const char *s0 = s;
+ long n;
+
+ switch (get8(s)) {
+ case ERL_LARGE_BIG_EXT:
+ n = get32be(s);
+ s += n+1;
+ break;
+
+ default:
+ erl_errno = EIO;
+ return -1;
+ }
+
+ *index += s-s0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/misc/show_msg.h b/lib/erl_interface/src/misc/show_msg.h
new file mode 100644
index 0000000000..fac51f3278
--- /dev/null
+++ b/lib/erl_interface/src/misc/show_msg.h
@@ -0,0 +1,27 @@
+/*
+ * %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%
+ *
+
+ */
+#ifndef _SHOW_MSG_H
+#define _SHOW_MSG_H
+
+void ei_show_recmsg(FILE *dest, erlang_msg *msg, char *buf);
+int ei_show_sendmsg(FILE *dest, const char *header, const char *msgbuf);
+
+#endif /* _SHOW_MSG_H */
diff --git a/lib/erl_interface/src/not_used/ei_send.c b/lib/erl_interface/src/not_used/ei_send.c
new file mode 100644
index 0000000000..2701b4404c
--- /dev/null
+++ b/lib/erl_interface/src/not_used/ei_send.c
@@ -0,0 +1,104 @@
+/*
+ * %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%
+ *
+
+ */
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+
+#elif VXWORKS
+#include <sys/types.h>
+#include <unistd.h>
+
+#else /* unix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#endif
+
+#include "eidef.h"
+#include "eiext.h"
+#include "ei_connect.h"
+#include "ei_internal.h"
+#include "putget.h"
+#include "ei_trace.h"
+#include "show_msg.h"
+
+/* FIXME this is not useed !!!!! */
+
+/* length (4), PASS_THROUGH (1), header, message */
+int ei_ei_send_encoded(ei_cnode* ec, int fd, const erlang_pid *to,
+ const char *msg, int msglen)
+{
+ char *s, header[1200]; /* see size calculation below */
+ erlang_trace *token = NULL;
+ int index = 5; /* reserve 5 bytes for control message */
+#ifdef HAVE_WRITEV
+ struct iovec v[2];
+#endif
+
+ /* are we tracing? */
+ /* check that he can receive trace tokens first */
+ if (ei_distversion(fd) > 0)
+ token = ei_trace(0,(erlang_trace *)NULL);
+
+ /* header = SEND, cookie, to max sizes: */
+ ei_encode_version(header,&index); /* 1 */
+ if (token) {
+ ei_encode_tuple_header(header,&index,4); /* 2 */
+ ei_encode_long(header,&index,ERL_SEND_TT); /* 2 */
+ } else {
+ ei_encode_tuple_header(header,&index,3);
+ ei_encode_long(header,&index,ERL_SEND);
+ }
+ ei_encode_atom(header,&index, "" /*ei_getfdcookie(ec, fd)*/); /* 258 */
+ ei_encode_pid(header,&index,to); /* 268 */
+
+ if (token) ei_encode_trace(header,&index,token); /* 534 */
+
+ /* control message (precedes header actually) */
+ /* length = 1 ('p') + header len + message len */
+ s = header;
+ put32be(s, index + msglen - 4); /* 4 */
+ put8(s, ERL_PASS_THROUGH); /* 1 */
+ /*** sum: 1070 */
+
+#ifdef DEBUG_DIST
+ if (ei_trace_distribution > 0) ei_show_sendmsg(stderr,header,msg);
+#endif
+
+#ifdef HAVE_WRITEV
+
+ v[0].iov_base = (char *)header;
+ v[0].iov_len = index;
+ v[1].iov_base = (char *)msg;
+ v[1].iov_len = msglen;
+
+ if (writev(fd,v,2) != index+msglen) return -1;
+
+#else /* !HAVE_WRITEV */
+
+ if (writesocket(fd,header,index) != index) return -1;
+ if (writesocket(fd,msg,msglen) != msglen) return -1;
+
+#endif /* !HAVE_WRITEV */
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/not_used/ei_send_reg.c b/lib/erl_interface/src/not_used/ei_send_reg.c
new file mode 100644
index 0000000000..af68549c6d
--- /dev/null
+++ b/lib/erl_interface/src/not_used/ei_send_reg.c
@@ -0,0 +1,107 @@
+/*
+ * %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%
+ *
+
+ */
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+
+#elif VXWORKS
+#include <sys/types.h>
+#include <unistd.h>
+
+#else /* unix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#endif
+
+#include "eidef.h"
+#include "eiext.h"
+#include "ei_connect.h"
+#include "ei_internal.h"
+#include "putget.h"
+#include "ei_trace.h"
+#include "show_msg.h"
+
+/* FIXME this is not useed !!!!! */
+/* FIXME merge with ei_send.c */
+
+/* length (4), PASS_THROUGH (1), header, message */
+int ei_ei_send_reg_encoded(ei_cnode* ec, int fd, const erlang_pid *from,
+ const char *to, const char *msg, int msglen)
+{
+ char *s, header[1400]; /* see size calculation below */
+ erlang_trace *token = NULL;
+ int index = 5; /* reserve 5 bytes for control message */
+#ifdef HAVE_WRITEV
+ struct iovec v[2];
+#endif
+
+ /* are we tracing? */
+ /* check that he can receive trace tokens first */
+ if (ei_distversion(fd) > 0)
+ token = ei_trace(0,(erlang_trace *)NULL);
+
+ /* header = REG_SEND, from, cookie, toname max sizes: */
+ ei_encode_version(header,&index); /* 1 */
+ if (token) {
+ ei_encode_tuple_header(header,&index,5); /* 2 */
+ ei_encode_long(header,&index,ERL_REG_SEND_TT); /* 2 */
+ } else {
+ ei_encode_tuple_header(header,&index,4);
+ ei_encode_long(header,&index,ERL_REG_SEND);
+ }
+ ei_encode_pid(header,&index,from); /* 268 */
+ ei_encode_atom(header,&index,"" /*ei_getfdcookie(ec, fd)*/ ); /* 258 */
+ ei_encode_atom(header,&index,to); /* 268 */
+
+ if (token) ei_encode_trace(header,&index,token); /* 534 */
+
+ /* control message (precedes header actually) */
+ /* length = 1 ('p') + header len + message len */
+ s = header;
+ put32be(s, index + msglen - 4); /* 4 */
+ put8(s, ERL_PASS_THROUGH); /* 1 */
+ /*** sum: 1336 */
+
+#ifdef DEBUG_DIST
+ if (ei_trace_distribution > 0) ei_show_sendmsg(stderr,header,msg);
+#endif
+
+#ifdef HAVE_WRITEV
+
+ v[0].iov_base = (char *)header;
+ v[0].iov_len = index;
+ v[1].iov_base = (char *)msg;
+ v[1].iov_len = msglen;
+
+ if (writev(fd,v,2) != index+msglen) return -1;
+
+#else
+
+ /* no writev() */
+ if (writesocket(fd,header,index) != index) return -1;
+ if (writesocket(fd,msg,msglen) != msglen) return -1;
+
+#endif
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/not_used/send_link.c b/lib/erl_interface/src/not_used/send_link.c
new file mode 100644
index 0000000000..4b43b2f0cc
--- /dev/null
+++ b/lib/erl_interface/src/not_used/send_link.c
@@ -0,0 +1,102 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+
+#elif VXWORKS
+#include <unistd.h>
+
+#else /* unix */
+#include <unistd.h>
+
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "eisend.h"
+#include "ei_internal.h"
+#include "putget.h"
+#include "erl_rport.h"
+
+
+/* this sends either link or unlink ('which' decides) */
+static int link_unlink(int fd, const erlang_pid *from, const erlang_pid *to,
+ int which, unsigned ms)
+{
+ char msgbuf[EISMALLBUF];
+ char *s;
+ int index = 0;
+ int n;
+
+ index = 5; /* max sizes: */
+ ei_encode_version(msgbuf,&index); /* 1 */
+ ei_encode_tuple_header(msgbuf,&index,3);
+ ei_encode_long(msgbuf,&index,which);
+ ei_encode_pid(msgbuf,&index,from); /* 268 */
+ ei_encode_pid(msgbuf,&index,to); /* 268 */
+
+ /* 5 byte header missing */
+ s = msgbuf;
+ put32be(s, index - 4); /* 4 */
+ put8(s, ERL_PASS_THROUGH); /* 1 */
+ /* sum: 542 */
+
+
+#ifdef DEBUG_DIST
+ if (ei_trace_distribution > 1) ei_show_sendmsg(stderr,msgbuf,NULL);
+#endif
+
+ n = ei_write_fill_t(fd,msgbuf,index,ms);
+
+ return (n==index ? 0 : -1);
+}
+
+/* FIXME not used? */
+#if 0
+/* use this to send a link */
+int ei_send_unlink(int fd, const erlang_pid *from, const erlang_pid *to)
+{
+ return link_unlink(fd, from, to, ERL_UNLINK,0);
+}
+
+/* use this to send an unlink */
+int ei_send_link(int fd, const erlang_pid *from, const erlang_pid *to)
+{
+ return link_unlink(fd, from, to, ERL_LINK,0);
+}
+/* use this to send a link */
+int ei_send_unlink_tmo(int fd, const erlang_pid *from, const erlang_pid *to,
+ unsigned ms)
+{
+ return link_unlink(fd, from, to, ERL_UNLINK,ms);
+}
+
+/* use this to send an unlink */
+int ei_send_link_tmo(int fd, const erlang_pid *from, const erlang_pid *to,
+ unsigned ms)
+{
+ return link_unlink(fd, from, to, ERL_LINK,ms);
+}
+#endif
diff --git a/lib/erl_interface/src/not_used/whereis.c b/lib/erl_interface/src/not_used/whereis.c
new file mode 100644
index 0000000000..a4dd73e952
--- /dev/null
+++ b/lib/erl_interface/src/not_used/whereis.c
@@ -0,0 +1,70 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+
+#elif VXWORKS
+#include <unistd.h>
+
+#else /* unix */
+#include <unistd.h>
+
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include "erl_interface.h"
+#include "erl_connect.h"
+#include "erl_format.h"
+#include "erl_eterm.h"
+#include "erl_malloc.h"
+
+/* FIXME rewrite to ei functions */
+/* FIXME not used */
+
+erlang_pid *erl_whereis(int fd, const char *name)
+{
+ ETERM *reply;
+ ETERM *n;
+ /* FIXME problem for threaded ? */
+ static erlang_pid pid;
+
+ n = erl_format("[~a]",name);
+ reply = erl_rpc(fd,"erlang","whereis",n);
+ erl_free_term(n);
+
+ if (reply && (ERL_IS_PID(reply))) {
+ char *node;
+ node = ERL_PID_NODE(reply);
+ strcpy(pid.node,node);
+ pid.num = ERL_PID_NUMBER(reply);
+ pid.serial = ERL_PID_SERIAL(reply);
+ pid.creation = ERL_PID_CREATION(reply);
+ erl_free_term(reply);
+ return &pid;
+ }
+
+ if (reply) erl_free_term(reply);
+ return NULL;
+}
+
diff --git a/lib/erl_interface/src/prog/ei_fake_prog.c b/lib/erl_interface/src/prog/ei_fake_prog.c
new file mode 100644
index 0000000000..68eb537211
--- /dev/null
+++ b/lib/erl_interface/src/prog/ei_fake_prog.c
@@ -0,0 +1,303 @@
+/*
+ * %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%
+ */
+
+/***************************************************************************
+ *
+ * This is a fake program that contains all functions, variables and
+ * defined symbols mentioned in the manual. We compile this file to see
+ * that the header files and created library is complete.
+ *
+ * You can't run this program, it is for compiling and linking only.
+ *
+ ***************************************************************************/
+
+/* This is a link and header file test. Including "ei.h" and linking
+ with libei.a should be enough */
+
+/* Use most of
+ * CFLAGS="-I../include -g -O2
+ * -ansi -pedantic
+ * -Wall
+ * -Wshadow
+ * -Wstrict-prototypes
+ * -Wmissing-prototypes
+ * -Wmissing-declarations
+ * -Wnested-externs
+ * -Winline
+ * -Werror"
+ */
+
+/* An exception from using eidef.h, use config.h directly */
+#include "config.h"
+
+#if defined(HAVE_GMP_H) && defined(HAVE_LIBGMP)
+#include <gmp.h>
+#endif /* HAVE_GMP_H && HAVE_LIBGMP */
+
+/* #include <netdb.h> now included by ei.h */
+#include "ei.h"
+
+#ifdef VXWORKS
+int ei_fake_prog_main(void)
+#else
+int main(void)
+#endif
+{
+ ErlConnect conp;
+ Erl_IpAddr thisipaddr = (Erl_IpAddr)0;
+ FILE *fp = (FILE *)0;
+ char* charp = "foo";
+ double *doublep = NULL;
+ double doublex = 0.0;
+ ei_cnode xec;
+ ei_reg *ei_regp = NULL;
+ ei_term eterm;
+ ei_x_buff eix;
+ erlang_big *bigp = NULL;
+ erlang_fun efun;
+ erlang_msg *msgp = NULL;
+ erlang_msg emsg;
+ erlang_pid *pidp = NULL;
+ erlang_pid epid;
+ erlang_port eport;
+ erlang_ref eref;
+ erlang_trace etrace;
+ int *intp = NULL;
+ int intx = 0;
+ long *longp = NULL;
+ long longx = 0;
+ short creation = 0;
+ struct ei_reg_stat *ei_reg_statp = NULL;
+ struct ei_reg_tabstat *ei_reg_tabstatp = NULL;
+ struct hostent *hostp = NULL;
+ unsigned char * ucharp = (unsigned char *)"foo";
+ unsigned long *ulongp = NULL;
+ unsigned long ulongx = 0;
+ void *voidp = NULL;
+#ifndef VXWORKS
+ EI_LONGLONG *longlongp = (EI_LONGLONG*)NULL;
+ EI_LONGLONG longlongx = 0;
+ EI_ULONGLONG *ulonglongp = (EI_ULONGLONG*)NULL;
+ EI_ULONGLONG ulonglongx = 0;
+#endif
+
+ intx = erl_errno;
+
+ ei_connect_init(&xec, charp, charp, creation);
+ ei_connect_xinit (&xec, charp, charp, charp, thisipaddr, charp, creation);
+
+ ei_connect(&xec, charp);
+ ei_xconnect (&xec, thisipaddr, charp);
+
+ ei_receive(intx, ucharp, intx);
+ ei_receive_msg(intx, &emsg, &eix);
+ ei_xreceive_msg(intx, &emsg, &eix);
+
+ ei_send(intx, &epid, charp, intx);
+ ei_reg_send(&xec, intx, charp, charp, intx);
+
+ ei_rpc(&xec, intx, charp, charp, charp, intx, &eix);
+ ei_rpc_to(&xec, intx, charp, charp, charp, intx);
+ ei_rpc_from(&xec, intx, intx, &emsg, &eix);
+
+ ei_publish(&xec, intx);
+ ei_accept(&xec, intx, &conp);
+ ei_unpublish(&xec);
+
+ ei_thisnodename(&xec);
+ ei_thishostname(&xec);
+ ei_thisalivename(&xec);
+
+ ei_self(&xec);
+
+ ei_gethostbyname(charp);
+ ei_gethostbyaddr(charp, intx, intx);
+ ei_gethostbyname_r(charp, hostp, charp, intx, intp);
+ ei_gethostbyaddr_r(charp, intx, intx, hostp, charp, intx, intp);
+
+ ei_encode_version(charp, intp);
+ ei_x_encode_version(&eix);
+ ei_encode_long(charp, intp, longx);
+ ei_x_encode_long(&eix, longx);
+ ei_encode_ulong(charp, intp, ulongx);
+ ei_x_encode_ulong(&eix, ulongx);
+ ei_encode_double(charp, intp, doublex);
+ ei_x_encode_double(&eix, doublex);
+ ei_encode_boolean(charp, intp, intx);
+ ei_x_encode_boolean(&eix, intx);
+ ei_encode_char(charp, intp, 'a');
+ ei_x_encode_char(&eix, 'a');
+ ei_encode_string(charp, intp, charp);
+ ei_encode_string_len(charp, intp, charp, intx);
+ ei_x_encode_string(&eix, charp);
+ ei_x_encode_string_len(&eix, charp, intx);
+ ei_encode_atom(charp, intp, charp);
+ ei_encode_atom_len(charp, intp, charp, intx);
+ ei_x_encode_atom(&eix, charp);
+ ei_x_encode_atom_len(&eix, charp, intx);
+ ei_encode_binary(charp, intp, (void *)0, longx);
+ ei_x_encode_binary(&eix, (void*)0, intx);
+ ei_encode_pid(charp, intp, &epid);
+ ei_x_encode_pid(&eix, &epid);
+ ei_encode_fun(charp, intp, &efun);
+ ei_x_encode_fun(&eix, &efun);
+ ei_encode_port(charp, intp, &eport);
+ ei_x_encode_port(&eix, &eport);
+ ei_encode_ref(charp, intp, &eref);
+ ei_x_encode_ref(&eix, &eref);
+ ei_encode_trace(charp, intp, &etrace);
+ ei_x_encode_trace(&eix, &etrace);
+ ei_encode_tuple_header(charp, intp, intx);
+ ei_x_encode_tuple_header(&eix, longx);
+ ei_encode_list_header(charp, intp, intx);
+ ei_x_encode_list_header(&eix, longx);
+/* #define ei_encode_empty_list(buf,i) ei_encode_list_header(buf,i,0) */
+ ei_x_encode_empty_list(&eix);
+
+ ei_get_type(charp, intp, intp, intp);
+ ei_get_type_internal(charp, intp, intp, intp);
+
+ ei_decode_version(charp, intp, intp);
+ ei_decode_long(charp, intp, longp);
+ ei_decode_ulong(charp, intp, ulongp);
+ ei_decode_double(charp, intp, doublep);
+ ei_decode_boolean(charp, intp, intp);
+ ei_decode_char(charp, intp, charp);
+ ei_decode_string(charp, intp, charp);
+ ei_decode_atom(charp, intp, charp);
+ ei_decode_binary(charp, intp, (void *)0, longp);
+ ei_decode_fun(charp, intp, &efun);
+ free_fun(&efun);
+ ei_decode_pid(charp, intp, &epid);
+ ei_decode_port(charp, intp, &eport);
+ ei_decode_ref(charp, intp, &eref);
+ ei_decode_trace(charp, intp, &etrace);
+ ei_decode_tuple_header(charp, intp, intp);
+ ei_decode_list_header(charp, intp, intp);
+
+ ei_decode_ei_term(charp, intp, &eterm);
+
+ ei_print_term(fp, charp, intp);
+ ei_s_print_term(&charp, charp, intp);
+
+ ei_x_format(&eix, charp);
+ ei_x_format_wo_ver(&eix, charp);
+
+ ei_x_new(&eix);
+ ei_x_new_with_version(&eix);
+ ei_x_free(&eix);
+ ei_x_append(&eix, &eix);
+ ei_x_append_buf(&eix, charp, intx);
+ ei_skip_term(charp, intp);
+
+ ei_reg_open(intx);
+ ei_reg_resize(ei_regp, intx);
+ ei_reg_close(ei_regp);
+
+ ei_reg_setival(ei_regp, charp, longx);
+ ei_reg_setfval(ei_regp, charp, doublex);
+ ei_reg_setsval(ei_regp, charp, charp);
+ ei_reg_setpval(ei_regp, charp, voidp, intx);
+
+ ei_reg_setval(ei_regp, charp, intx);
+
+ ei_reg_getival(ei_regp, charp);
+ ei_reg_getfval(ei_regp, charp);
+ ei_reg_getsval(ei_regp, charp);
+ ei_reg_getpval(ei_regp, charp, intp);
+
+ ei_reg_getval(ei_regp, charp, intx);
+
+ ei_reg_markdirty(ei_regp, charp);
+
+ ei_reg_delete(ei_regp, charp);
+
+ ei_reg_stat(ei_regp, charp, ei_reg_statp);
+
+ ei_reg_tabstat(ei_regp, ei_reg_tabstatp);
+
+ ei_reg_dump(intx, ei_regp, charp, intx);
+ ei_reg_restore(intx, ei_regp, charp);
+ ei_reg_purge(ei_regp);
+
+#if defined(HAVE_GMP_H) && defined(HAVE_LIBGMP)
+ {
+ mpz_t obj;
+ ei_decode_bignum(charp, intp, obj);
+ ei_encode_bignum(charp, intp, obj);
+ ei_x_encode_bignum(&eix, obj);
+ }
+#endif /* HAVE_GMP_H && HAVE_LIBGMP */
+
+#ifndef VXWORKS
+
+ ei_decode_longlong(charp, intp, longlongp);
+ ei_decode_ulonglong(charp, intp, ulonglongp);
+ ei_encode_longlong(charp, intp, longlongx);
+ ei_encode_ulonglong(charp, intp, ulonglongx);
+ ei_x_encode_longlong(&eix, longlongx);
+ ei_x_encode_ulonglong(&eix, ulonglongx);
+
+#endif
+
+#ifdef USE_EI_UNDOCUMENTED
+
+ ei_decode_intlist(charp, intp, longp, intp);
+
+ ei_receive_encoded(intx, &charp, intp, msgp, intp);
+ ei_send_encoded(intx, pidp, charp, intx);
+ ei_send_reg_encoded(intx, pidp, charp, charp, intx);
+
+ ei_decode_big(charp, intp, bigp);
+ ei_big_comp(bigp, bigp);
+ ei_big_to_double(bigp, doublep);
+ ei_small_to_big(intx, bigp);
+ ei_alloc_big(intx);
+ ei_free_big(bigp);
+
+#endif /* USE_EI_UNDOCUMENTED */
+
+ return
+ BUFSIZ +
+ EAGAIN +
+ EHOSTUNREACH +
+ EIO +
+ EI_BIN +
+ EI_DELET +
+ EI_DIRTY +
+ EI_FLT +
+ EI_FORCE +
+ EI_INT +
+ EI_NOPURGE +
+ EI_STR +
+ EMSGSIZE +
+ ENOMEM +
+ ERL_ERROR +
+ ERL_EXIT +
+ ERL_LINK +
+ ERL_MSG +
+ ERL_NO_TIMEOUT +
+ ERL_REG_SEND +
+ ERL_SEND +
+ ERL_TICK +
+ ERL_TIMEOUT +
+ ERL_UNLINK +
+ ETIMEDOUT +
+ MAXATOMLEN;
+}
diff --git a/lib/erl_interface/src/prog/erl_call.c b/lib/erl_interface/src/prog/erl_call.c
new file mode 100644
index 0000000000..f0d638324d
--- /dev/null
+++ b/lib/erl_interface/src/prog/erl_call.c
@@ -0,0 +1,906 @@
+/*
+ * %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%
+ *
+
+ */
+/*
+ * Function: Makes it possible to send and receive Erlang
+ * messages from the (Unix) command line.
+ * Note: We don't free any memory at all since we only
+ * live for a short while.
+ *
+ */
+
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <direct.h>
+#include <windows.h>
+#include <winbase.h>
+
+#elif VXWORKS
+
+#include <stdio.h>
+#include <string.h>
+#include <vxWorks.h>
+#include <hostLib.h>
+#include <selectLib.h>
+#include <ifLib.h>
+#include <sockLib.h>
+#include <taskLib.h>
+#include <inetLib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <time.h>
+
+#else /* unix */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <netdb.h>
+#include <sys/times.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "ei.h"
+#include "ei_resolve.h"
+#include "erl_start.h" /* FIXME remove dependency */
+
+#ifdef __WIN32__
+static void initWinSock(void);
+#endif
+
+/*
+ * Some nice global variables
+ * (I don't think "nice" is the right word actually... -gordon)
+ */
+/* FIXME problem for threaded ? */
+
+struct call_flags {
+ int startp;
+ int cookiep;
+ int modp;
+ int evalp;
+ int randomp;
+ int use_long_name; /* indicates if -name was used, else -sname or -n */
+ int debugp;
+ int verbosep;
+ int haltp;
+ char *cookie;
+ char *node;
+ char *hidden;
+ char *apply;
+ char *script;
+};
+
+static void usage_arg(const char *progname, const char *switchname);
+static void usage_error(const char *progname, const char *switchname);
+static void usage(const char *progname);
+static int get_module(char **mbuf, char **mname);
+static struct hostent* get_hostent(char *host);
+static int do_connect(ei_cnode *ec, char *nodename, struct call_flags *flags);
+static int read_stdin(char **buf);
+static void split_apply_string(char *str, char **mod,
+ char **fun, char **args);
+
+
+/***************************************************************************
+ *
+ * XXXXX
+ *
+ ***************************************************************************/
+
+/* FIXME isn't VxWorks to handle arguments differently? */
+/* FIXME check errors from malloc */
+
+#if !defined(VXWORKS)
+int main(int argc, char *argv[])
+#else
+int erl_call(int argc, char **argv)
+#endif
+{
+ int i = 1,fd,creation;
+ struct hostent *hp;
+ char host_name[EI_MAXHOSTNAMELEN+1];
+ char nodename[MAXNODELEN+1];
+ char *p = NULL;
+ char *ct = NULL; /* temporary used when truncating nodename */
+ int modsize = 0;
+ char *host = NULL;
+ char *module = NULL;
+ char *modname = NULL;
+ struct call_flags flags = {0}; /* Default 0 and NULL in all fields */
+ char* progname = argv[0];
+ ei_cnode ec;
+
+ /* Get the command line options */
+ while (i < argc) {
+ if (argv[i][0] != '-') {
+ usage_error(progname, argv[i]);
+ }
+
+ if (strcmp(argv[i], "-sname") == 0) { /* -sname NAME */
+ if (i+1 >= argc) {
+ usage_arg(progname, "-sname ");
+ }
+
+ flags.node = (char *) malloc(strlen(argv[i+1]) + 1);
+ strcpy(flags.node, argv[i+1]);
+ i++;
+ flags.use_long_name = 0;
+ } else if (strcmp(argv[i], "-name") == 0) { /* -name NAME */
+ if (i+1 >= argc) {
+ usage_arg(progname, "-name ");
+ }
+
+ flags.node = (char *) malloc(strlen(argv[i+1]) + 1);
+ strcpy(flags.node, argv[i+1]);
+ i++;
+ flags.use_long_name = 1;
+ } else {
+ if (strlen(argv[i]) != 2) {
+ usage_error(progname, argv[i]);
+ }
+
+ switch (argv[i][1]) {
+ case 's':
+ flags.startp = 1;
+ break;
+ case 'q':
+ flags.haltp = 1;
+ break;
+ case 'v':
+ flags.verbosep = 1;
+ break;
+ case 'd':
+ flags.debugp = 1;
+ break;
+ case 'r':
+ flags.randomp = 1;
+ break;
+ case 'e':
+ flags.evalp = 1;
+ break;
+ case 'm':
+ flags.modp = 1;
+ break;
+ case 'c':
+ if (i+1 >= argc) {
+ usage_arg(progname, "-c ");
+ }
+ flags.cookiep = 1;
+ flags.cookie = (char *) malloc(strlen(argv[i+1]) + 1);
+ strcpy(flags.cookie, argv[i+1]);
+ i++;
+ break;
+ case 'n':
+ if (i+1 >= argc) {
+ usage_arg(progname, "-n ");
+ }
+ flags.node = (char *) malloc(strlen(argv[i+1]) + 1);
+ strcpy(flags.node, argv[i+1]);
+ flags.use_long_name = 1;
+ i++;
+ break;
+ case 'h':
+ if (i+1 >= argc) {
+ usage_arg(progname, "-h ");
+ }
+ flags.hidden = (char *) malloc(strlen(argv[i+1]) + 1);
+ strcpy(flags.hidden, argv[i+1]);
+ i++;
+ break;
+ case 'x':
+ if (i+1 >= argc) {
+ usage_arg(progname, "-x ");
+ }
+ flags.script = (char *) malloc(strlen(argv[i+1]) + 1);
+ strcpy(flags.script, argv[i+1]);
+ i++;
+ break;
+ case 'a':
+ if (i+1 >= argc) {
+ usage_arg(progname, "-a ");
+ }
+ flags.apply = (char *) malloc(strlen(argv[i+1]) + 1);
+ strcpy(flags.apply, argv[i+1]);
+ i++;
+ break;
+ case '?':
+ usage(progname);
+ default:
+ usage_error(progname, argv[i]);
+ }
+ }
+ i++;
+
+ } /* while */
+
+
+ /*
+ * Can't have them both !
+ */
+ if (flags.modp && flags.evalp) {
+ usage(progname);
+ }
+
+ /*
+ * Read an Erlang module from stdin.
+ */
+ if (flags.modp) {
+ modsize = get_module(&module, &modname);
+ }
+
+ if (flags.verbosep || flags.debugp) {
+ fprintf(stderr,"erl_call: "
+ "node = %s\nCookie = %s\n"
+ "flags = %s %s %s\n"
+ "module: name = %s , size = %d\n"
+ "apply = %s\n",
+ (flags.node ? flags.node : ""),
+ (flags.cookie ? flags.cookie : ""),
+ (flags.startp ? "startp" : ""),
+ (flags.verbosep ? "verbosep" : ""),
+ (flags.debugp ? "debugp" : ""),
+ (modname ? modname : ""), modsize,
+ (flags.apply ? flags.apply : "" ));
+ }
+
+ /*
+ * What we, at least, requires !
+ */
+ if (flags.node == NULL) {
+ usage(progname);
+ }
+
+ if (!flags.cookiep) {
+ flags.cookie = NULL;
+ }
+
+ /* FIXME decide how many bits etc or leave to connect_xinit? */
+ creation = (time(NULL) % 3) + 1; /* "random" */
+
+ if (flags.hidden == NULL) {
+ /* As default we are c17@gethostname */
+ i = flags.randomp ? (time(NULL) % 997) : 17;
+ /* FIXME allocates to small !!! */
+ flags.hidden = (char *) malloc(3 + 2 ); /* c17 or cXYZ */
+#if defined(VXWORKS)
+ sprintf(flags.hidden, "c%d",
+ i < 0 ? (int) taskIdSelf() : i);
+#else
+ sprintf(flags.hidden, "c%d",
+ i < 0 ? (int) getpid() : i);
+#endif
+ }
+ {
+ /* A name for our hidden node was specified */
+ char h_hostname[EI_MAXHOSTNAMELEN+1];
+ char h_nodename[MAXNODELEN+1];
+ char *h_alivename=flags.hidden;
+ struct in_addr h_ipadr;
+ char* ct;
+
+#ifdef __WIN32__
+ /*
+ * FIXME Extremly ugly, but needed to get ei_gethostbyname() below
+ * to work.
+ */
+ initWinSock();
+#endif
+
+ gethostname(h_hostname, EI_MAXHOSTNAMELEN);
+ if ((hp = ei_gethostbyname(h_hostname)) == 0) {
+ fprintf(stderr,"erl_call: can't resolve hostname %s\n", h_hostname);
+ exit(1);
+ }
+ /* If shortnames cut of the name at first '.' */
+ if (flags.use_long_name == 0 && (ct = strchr(hp->h_name, '.')) != NULL) {
+ *ct = '\0';
+ }
+ strcpy(h_hostname, hp->h_name);
+ memcpy(&h_ipadr.s_addr, *hp->h_addr_list, sizeof(struct in_addr));
+ sprintf(h_nodename, "%s@%s", h_alivename, h_hostname);
+
+ if (ei_connect_xinit(&ec, h_hostname, h_alivename, h_nodename,
+ (Erl_IpAddr)&h_ipadr, flags.cookie,
+ (short) creation) < 0) {
+ fprintf(stderr,"erl_call: can't create C node %s; %d\n",
+ h_nodename, erl_errno);
+ exit(1);
+ }
+
+ }
+ if ((p = strchr((const char *)flags.node, (int) '@')) == 0) {
+ strcpy(host_name, ei_thishostname(&ec));
+ host = host_name;
+ } else {
+ *p = 0;
+ host = p+1;
+ }
+
+ /*
+ * Expand name to a real name (may be ip-address)
+ */
+ /* FIXME better error string */
+ if ((hp = get_hostent(host)) == 0) {
+ fprintf(stderr,"erl_call: can't get_hostent(%s)\n", host);
+ exit(1);
+ }
+ /* If shortnames cut of the name at first '.' */
+ if (flags.use_long_name == 0 && (ct = strchr(hp->h_name, '.')) != NULL) {
+ *ct = '\0';
+ }
+ strcpy(host_name, hp->h_name);
+ sprintf(nodename, "%s@%s", flags.node, host_name);
+
+ /*
+ * Try to connect. Start an Erlang system if the
+ * start option is on and no system is running.
+ */
+ if (flags.startp && !flags.haltp) {
+ fd = do_connect(&ec, nodename, &flags);
+ } else if ((fd = ei_connect(&ec, nodename)) < 0) {
+ /* We failed to connect ourself */
+ /* FIXME do we really know we failed because of node not up? */
+ if (flags.haltp) {
+ exit(0);
+ } else {
+ fprintf(stderr,"erl_call: failed to connect to node %s\n",
+ nodename);
+ exit(1);
+ }
+ }
+
+ /* If we are connected and the halt switch is set */
+ if (fd && flags.haltp) {
+ int i = 0;
+ char *p;
+ ei_x_buff reply;
+
+ ei_encode_empty_list(NULL, &i);
+
+ p = (char *)malloc(i);
+ i = 0; /* Reset */
+
+ ei_encode_empty_list(p, &i);
+
+ ei_x_new_with_version(&reply);
+
+ /* FIXME if fails we want to exit != 0 ? */
+ ei_rpc(&ec, fd, "erlang", "halt", p, i, &reply);
+ free(p);
+ ei_x_free(&reply);
+ exit(0);
+ }
+
+ if (flags.verbosep) {
+ fprintf(stderr,"erl_call: we are now connected to node \"%s\"\n",
+ nodename);
+ }
+
+ /*
+ * Compile the module read from stdin.
+ */
+ if (flags.modp && (modname != NULL)) {
+ char fname[256];
+
+ strcpy(fname, modname);
+ strcat(fname, ".erl");
+
+ /*
+ * ei_format("[~s,~w]", fname, erl_mk_binary(module, modsize));
+ */
+
+ {
+ int i = 0;
+ char *p;
+ ei_x_buff reply;
+
+ ei_encode_list_header(NULL, &i, 2);
+ ei_encode_string(NULL, &i, fname);
+ ei_encode_binary(NULL, &i, module, modsize);
+ ei_encode_empty_list(NULL, &i);
+
+ p = (char *)malloc(i);
+ i = 0; /* Reset */
+
+ ei_encode_list_header(p, &i, 2);
+ ei_encode_string(p, &i, fname);
+ ei_encode_binary(p, &i, module, modsize);
+ ei_encode_empty_list(p, &i);
+
+ ei_x_new_with_version(&reply);
+
+ if (ei_rpc(&ec, fd, "file", "write_file", p, i, &reply) < 0) {
+ free(p);
+ ei_x_free(&reply);
+ fprintf(stderr,"erl_call: can't write to source file %s\n",
+ fname);
+ exit(1);
+ }
+ free(p);
+ ei_x_free(&reply);
+ }
+
+ /* Compile AND load file on other node */
+
+ {
+ int i = 0;
+ char *p;
+ ei_x_buff reply;
+
+ ei_encode_list_header(NULL, &i, 2);
+ ei_encode_atom(NULL, &i, fname);
+ ei_encode_empty_list(NULL, &i);
+ ei_encode_empty_list(NULL, &i);
+
+ p = (char *)malloc(i);
+ i = 0; /* Reset */
+
+ ei_encode_list_header(p, &i, 2);
+ ei_encode_atom(p, &i, fname);
+ ei_encode_empty_list(p, &i);
+ ei_encode_empty_list(p, &i);
+
+ ei_x_new_with_version(&reply);
+
+ /* erl_format("[~a,[]]", modname) */
+
+ if (ei_rpc(&ec, fd, "c", "c", p, i, &reply) < 0) {
+ free(p);
+ ei_x_free(&reply);
+ fprintf(stderr,"erl_call: can't compile file %s\n", fname);
+ }
+ free(p);
+ /* FIXME complete this code
+ FIXME print out error message as term
+ if (!erl_match(erl_format("{ok,_}"), reply)) {
+ fprintf(stderr,"erl_call: compiler errors\n");
+ }
+ */
+ ei_x_free(&reply);
+ }
+
+ }
+ /*
+ * Eval the Erlang functions read from stdin/
+ */
+ if (flags.evalp) {
+ char *evalbuf;
+ int len;
+
+ len = read_stdin(&evalbuf);
+ {
+ int i = 0;
+ char *p;
+ ei_x_buff reply;
+
+ ei_encode_list_header(NULL, &i, 1);
+ ei_encode_binary(NULL, &i, evalbuf, len);
+ ei_encode_empty_list(NULL, &i);
+
+ p = (char *)malloc(i);
+ i = 0; /* Reset */
+
+ ei_encode_list_header(p, &i, 1);
+ ei_encode_binary(p, &i, evalbuf, len);
+ ei_encode_empty_list(p, &i);
+
+ ei_x_new_with_version(&reply);
+
+ /* erl_format("[~w]", erl_mk_binary(evalbuf,len))) */
+
+ if (ei_rpc(&ec, fd, "lib", "eval_str", p, i, &reply) < 0) {
+ fprintf(stderr,"erl_call: evaluating input failed: %s\n",
+ evalbuf);
+ free(p);
+ free(evalbuf); /* Allocated in read_stdin() */
+ ei_x_free(&reply);
+ exit(1);
+ }
+ i = 0;
+ ei_print_term(stdout,reply.buff,&i);
+ free(p);
+ free(evalbuf); /* Allocated in read_stdin() */
+ ei_x_free(&reply);
+ }
+ }
+ /*
+ * Any Erlang call to be made ?
+ */
+ if (flags.apply != NULL) {
+ char *mod,*fun,*args;
+ ei_x_buff e, reply;
+
+ split_apply_string(flags.apply, &mod, &fun, &args);
+ if (flags.verbosep) {
+ fprintf(stderr,"erl_call: module = %s, function = %s, args = %s\n",
+ mod, fun, args);
+ }
+
+ ei_x_new(&e); /* No version to ei_rpc() */
+
+ if (ei_x_format_wo_ver(&e, args) < 0) {
+ /* FIXME no error message and why -1 ? */
+ exit(-1);
+ }
+
+ ei_x_new_with_version(&reply);
+
+ if (ei_rpc(&ec, fd, mod, fun, e.buff, e.index, &reply) < 0) {
+ /* FIXME no error message and why -1 ? */
+ ei_x_free(&e);
+ ei_x_free(&reply);
+ exit(-1);
+ } else {
+ int i = 0;
+ ei_print_term(stdout,reply.buff,&i);
+ ei_x_free(&e);
+ ei_x_free(&reply);
+ }
+ }
+
+ return(0);
+}
+
+
+/***************************************************************************
+ *
+ * XXXXX
+ *
+ ***************************************************************************/
+
+/*
+ * Get host entry (by address or name)
+ */
+/* FIXME: will fail on names like '2fun4you'. */
+static struct hostent* get_hostent(char *host)
+{
+ if (isdigit((int)*host)) {
+ struct in_addr ip_addr;
+ int b1, b2, b3, b4;
+ long addr;
+
+ /* FIXME: Use inet_aton() (or inet_pton() and get v6 for free). */
+ if (sscanf(host, "%d.%d.%d.%d", &b1, &b2, &b3, &b4) != 4) {
+ return NULL;
+ }
+ addr = inet_addr(host);
+ ip_addr.s_addr = htonl(addr);
+
+ return ei_gethostbyaddr((char *)&ip_addr,sizeof(struct in_addr), AF_INET);
+ }
+
+ return ei_gethostbyname(host);
+} /* get_hostent */
+
+
+
+
+/*
+ * This function does only return on success.
+ */
+static int do_connect(ei_cnode *ec, char *nodename, struct call_flags *flags)
+{
+ int fd;
+ int start_flags;
+ int r;
+
+ start_flags = ERL_START_ENODE |
+ (flags->use_long_name? ERL_START_LONG : 0) |
+ (flags->verbosep? ERL_START_VERBOSE : 0) |
+ (flags->debugp? ERL_START_DEBUG : 0);
+
+ if ((fd = ei_connect(ec, nodename)) >= 0) {
+ /* success */
+ if (flags->verbosep) {
+ fprintf(stderr,"erl_call: now connected to node %s\n", nodename);
+ }
+ } else {
+ char alive[EI_MAXALIVELEN+1];
+ char *hostname;
+ struct hostent *h;
+ char *cookieargs[3];
+ char **args;
+
+ cookieargs[0] = "-setcookie";
+ cookieargs[1] = flags->cookie;
+ cookieargs[2] = NULL;
+
+ args = (flags->cookie) ? cookieargs : NULL;
+
+ if (!(hostname = strrchr(nodename,'@'))) {
+ return ERL_BADARG;
+ }
+ strncpy(alive,nodename,hostname-nodename);
+ alive[hostname-nodename] = 0x0;
+ hostname++;
+
+ h = ei_gethostbyname(hostname);
+
+
+ if ((r=erl_start_sys(ec,alive,(Erl_IpAddr)(h->h_addr_list[0]),
+ start_flags,flags->script,args)) < 0) {
+ fprintf(stderr,"erl_call: unable to start node, error = %d\n", r);
+ exit(1);
+ }
+
+ if ((fd=ei_connect(ec, nodename)) >= 0) {
+ /* success */
+ if (flags->verbosep) {
+ fprintf(stderr,"erl_call: now connected to node \"%s\"\n",
+ nodename);
+ }
+ } else {
+ /* (failure) */
+ switch (fd) {
+ case ERL_NO_DAEMON:
+ fprintf(stderr,"erl_call: no epmd running\n");
+ exit(1);
+ case ERL_CONNECT_FAIL:
+ fprintf(stderr,"erl_call: connect failed\n");
+ exit(1);
+ case ERL_NO_PORT:
+ fprintf(stderr,"erl_call: node is not running\n");
+ exit(1);
+ case ERL_TIMEOUT:
+ fprintf(stderr,"erl_call: connect timed out\n");
+ exit(1);
+ default:
+ fprintf(stderr,"erl_call: error during connect\n");
+ exit(1);
+ }
+ }
+ }
+
+ return fd;
+} /* do_connect */
+
+#define SKIP_SPACE(s) while(isspace((int)*(s))) (s)++
+#define EAT(s) while (!isspace((int)*(s)) && (*(s) != '\0')) (s)++
+
+static void split_apply_string(char *str,
+ char **mod,
+ char **fun,
+ char **args)
+{
+ char *begin=str;
+ char *start="start";
+ char *empty_list="[]";
+ int len;
+
+ SKIP_SPACE(str);
+ if (*str == '\0') {
+ fprintf(stderr,"erl_call: wrong format of apply string (1)\n");
+ exit(1);
+ }
+
+ EAT(str);
+ len = str-begin;
+ *mod = (char *) calloc(len + 1, sizeof(char));
+ memcpy(*mod, begin, len);
+
+ SKIP_SPACE(str);
+ if (*str == '\0') {
+ *fun = (char *) calloc(strlen(start)+1, sizeof(char));
+ strcpy(*fun, start);
+ *args = (char *) calloc(strlen(empty_list)+1, sizeof(char));
+ strcpy(*args, empty_list);
+ return;
+ }
+ begin = str;
+ EAT(str);
+ len = str-begin;
+ *fun = (char *) calloc(len + 1, sizeof(char));
+ memcpy(*fun, begin, len);
+
+ SKIP_SPACE(str);
+ if (*str == '\0') {
+ *args = (char *) calloc(strlen(empty_list)+1, sizeof(char));
+ strcpy(*args, empty_list);
+ return;
+ }
+
+ *args = (char *) calloc(strlen(str) + 1, sizeof(char));
+ strcpy(*args, str);
+
+ return;
+
+} /* split_apply_string */
+
+
+/*
+ * Read from stdin until EOF is reached.
+ * Allocate the buffer needed.
+ */
+static int read_stdin(char **buf)
+{
+ int bsize = BUFSIZ;
+ int len = 0;
+ int i;
+ char *tmp = (char *) malloc(bsize);
+
+ while (1) {
+ if ((i = read(0, &tmp[len], bsize-len)) < 0) {
+ fprintf(stderr,"erl_call: can't read stdin, errno = %d", errno);
+ exit(1);
+ } else if (i == 0) {
+ break;
+ } else {
+ len += i;
+ if ((len+50) > bsize) {
+ bsize = len * 2;
+ tmp = (char *) realloc(tmp, bsize);
+ } else {
+ continue;
+ }
+ }
+ } /* while */
+ *buf = tmp;
+ return len;
+
+} /* read_stdin */
+
+/*
+ * Get the module from stdin.
+ */
+static int get_module(char **mbuf, char **mname)
+{
+ char *tmp;
+ int len,i;
+
+ len = read_stdin(mbuf);
+ /*
+ * Now, get the module name.
+ */
+ if ((tmp = strstr(*mbuf, "-module(")) != NULL) {
+ char *start;
+ tmp += strlen("-module(");
+ while ((*tmp) == ' ') tmp++; /* eat space */
+ start = tmp;
+ while (1) {
+ if (isalnum((int)*tmp) || (*tmp == '_')) {
+ tmp++;
+ continue;
+ } else {
+ break;
+ }
+ } /* while */
+ i = tmp - start;
+ *mname = (char *) calloc(i+1, sizeof(char));
+ memcpy(*mname, start, i);
+ }
+ free(mbuf); /* Allocated in read_stdin() */
+
+ return len;
+
+} /* get_module */
+
+
+/***************************************************************************
+ *
+ * Different error reporting functions that output usage
+ *
+ ***************************************************************************/
+
+static void usage_noexit(const char *progname) {
+ fprintf(stderr,"\nUsage: %s [-[demqrsv]] [-c Cookie] [-h HiddenName] \n", progname);
+ fprintf(stderr," [-x ErlScript] [-a [Mod [Fun [Args]]]]\n");
+ fprintf(stderr," (-n Node | -sname Node | -name Node)\n\n");
+#ifdef __WIN32__
+ fprintf(stderr," where: -a apply(Mod,Fun,Args) (e.g -a \"erlang length [[a,b,c]]\"\n");
+#else
+ fprintf(stderr," where: -a apply(Mod,Fun,Args) (e.g -a 'erlang length [[a,b,c]]'\n");
+#endif
+ fprintf(stderr," -c cookie string; by default read from ~/.erlang.cookie\n");
+ fprintf(stderr," -d direct Erlang output to ~/.erl_call.out.<Nodename>\n");
+ fprintf(stderr," -e evaluate contents of standard input (e.g echo \"X=1,Y=2,{X,Y}.\"|erl_call -e ...)\n");
+ fprintf(stderr," -h specify a name for the erl_call client node\n");
+ fprintf(stderr," -m read and compile Erlang module from stdin\n");
+ fprintf(stderr," -n name of Erlang node, same as -name\n");
+ fprintf(stderr," -name name of Erlang node, expanded to a fully qualified\n");
+ fprintf(stderr," -sname name of Erlang node, short form will be used\n");
+ fprintf(stderr," -q halt the Erlang node (overrides the -s switch)\n");
+ fprintf(stderr," -r use a random name for the erl_call client node\n");
+ fprintf(stderr," -s start a new Erlang node if necessary\n");
+ fprintf(stderr," -v verbose mode, i.e print some information on stderr\n");
+ fprintf(stderr," -x use specified erl start script, default is erl\n");
+}
+
+static void usage_arg(const char *progname, const char *switchname) {
+ fprintf(stderr, "Missing argument(s) for \'%s\'.\n", switchname);
+ usage_noexit(progname);
+ exit(1);
+}
+
+static void usage_error(const char *progname, const char *switchname) {
+ fprintf(stderr, "Illegal argument \'%s\'.\n", switchname);
+ usage_noexit(progname);
+ exit(1);
+}
+
+static void usage(const char *progname) {
+ usage_noexit(progname);
+ exit(0);
+}
+
+
+/***************************************************************************
+ *
+ * OS specific functions
+ *
+ ***************************************************************************/
+
+#ifdef __WIN32__
+/*
+ * FIXME This should not be here. This is a quick fix to make erl_call
+ * work at all on Windows NT.
+ */
+static void initWinSock(void)
+{
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int err;
+ static int initialized;
+
+ wVersionRequested = MAKEWORD(1, 1);
+ if (!initialized) {
+ initialized = 1;
+ err = WSAStartup(wVersionRequested, &wsaData);
+
+ if (err != 0) {
+ fprintf(stderr,"erl_call: "
+ "Can't initialize windows sockets: %d\n", err);
+ }
+
+ if ( LOBYTE( wsaData.wVersion ) != 1 ||
+ HIBYTE( wsaData.wVersion ) != 1 ) {
+ fprintf(stderr,"erl_call: This version of "
+ "windows sockets not supported\n");
+ WSACleanup();
+ }
+ }
+}
+#endif
diff --git a/lib/erl_interface/src/prog/erl_fake_prog.c b/lib/erl_interface/src/prog/erl_fake_prog.c
new file mode 100644
index 0000000000..a2b49a0ed9
--- /dev/null
+++ b/lib/erl_interface/src/prog/erl_fake_prog.c
@@ -0,0 +1,250 @@
+/*
+ * %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%
+ */
+
+/***************************************************************************
+ *
+ * This is a fake program that contains all functions, variables and
+ * defined symbols mentioned in the manual. We compile this file to see
+ * that the header files and created library is complete.
+ *
+ * You can't run this program, it is for compiling and linking only.
+ *
+ ***************************************************************************/
+
+/* Use most of
+ * CFLAGS="-I../include -g -O2
+ * -ansi -pedantic
+ * -Wall
+ * -Wshadow
+ * -Wstrict-prototypes
+ * -Wmissing-prototypes
+ * -Wmissing-declarations
+ * -Wnested-externs
+ * -Winline
+ * -Werror"
+ */
+
+/* #include <netdb.h> now included by ei.h */
+#include "erl_interface.h"
+
+#ifdef VXWORKS
+int erl_fake_prog_main(void)
+#else
+int main(void)
+#endif
+{
+ ei_x_buff eix;
+ int index = 0;
+ ETERM **etermpp = NULL, *etermp = NULL;
+ char *charp = NULL;
+ unsigned char uchar, **ucharpp = NULL, *ucharp = NULL;
+ void *voidp = NULL;
+ Erl_Heap *erl_heapp = NULL;
+ int intx = 0;
+ int *intp = NULL;
+ unsigned int uintx, *uintp;
+ unsigned long *ulongp = NULL;
+ long longx = 0;
+ double doublex = 0.0;
+ short shortx = 42;
+ FILE *filep = NULL;
+ Erl_IpAddr erl_ipaddr = NULL;
+ ErlMessage *erlmessagep = NULL;
+ ErlConnect *erlconnectp = NULL;
+ struct hostent *hostp = NULL;
+ struct in_addr *inaddrp = NULL;
+
+ /* Converion to erl_interface format is in liberl_interface */
+
+ intx = erl_errno;
+
+ ei_encode_term(charp, &index, voidp);
+ ei_x_encode_term(&eix, voidp);
+ ei_decode_term(charp, &index, voidp);
+
+ erl_init(voidp, longx);
+ erl_connect_init(intx, charp,shortx);
+ erl_connect_xinit(charp,charp,charp,erl_ipaddr,charp,shortx);
+ erl_connect(charp);
+ erl_xconnect(erl_ipaddr,charp);
+ erl_close_connection(intx);
+ erl_receive(intx, ucharp, intx);
+ erl_receive_msg(intx, ucharp, intx, erlmessagep);
+ erl_xreceive_msg(intx, ucharpp, intp, erlmessagep);
+ erl_send(intx, etermp, etermp);
+ erl_reg_send(intx, charp, etermp);
+ erl_rpc(intx,charp,charp,etermp);
+ erl_rpc_to(intx,charp,charp,etermp);
+ erl_rpc_from(intx,intx,erlmessagep);
+
+ erl_publish(intx);
+ erl_accept(intx,erlconnectp);
+
+ erl_thiscookie();
+ erl_thisnodename();
+ erl_thishostname();
+ erl_thisalivename();
+ erl_thiscreation();
+ erl_unpublish(charp);
+ erl_err_msg(charp);
+ erl_err_quit(charp);
+ erl_err_ret(charp);
+ erl_err_sys(charp);
+
+ erl_cons(etermp,etermp);
+ erl_copy_term(etermp);
+ erl_element(intx,etermp);
+
+ erl_hd(etermp);
+ erl_iolist_to_binary(etermp);
+ erl_iolist_to_string(etermp);
+ erl_iolist_length(etermp);
+ erl_length(etermp);
+ erl_mk_atom(charp);
+ erl_mk_binary(charp,intx);
+ erl_mk_empty_list();
+ erl_mk_estring(charp, intx);
+ erl_mk_float(doublex);
+ erl_mk_int(intx);
+ erl_mk_list(etermpp,intx);
+ erl_mk_pid(charp,uintx,uintx,uchar);
+ erl_mk_port(charp,uintx,uchar);
+ erl_mk_ref(charp,uintx,uchar);
+ erl_mk_long_ref(charp,uintx,uintx,uintx,uchar);
+ erl_mk_string(charp);
+ erl_mk_tuple(etermpp,intx);
+ erl_mk_uint(uintx);
+ erl_mk_var(charp);
+ erl_print_term(filep,etermp);
+ /* erl_sprint_term(charp,etermp); */
+ erl_size(etermp);
+ erl_tl(etermp);
+ erl_var_content(etermp, charp);
+
+ erl_format(charp);
+ erl_match(etermp, etermp);
+
+ erl_global_names(intx, intp);
+ erl_global_register(intx, charp, etermp);
+ erl_global_unregister(intx, charp);
+ erl_global_whereis(intx, charp, charp);
+
+ erl_init_malloc(erl_heapp,longx);
+ erl_alloc_eterm(uchar);
+ erl_eterm_release();
+ erl_eterm_statistics(ulongp,ulongp);
+ erl_free_array(etermpp,intx);
+ erl_free_term(etermp);
+ erl_free_compound(etermp);
+ erl_malloc(longx);
+ erl_free(voidp);
+
+ erl_compare_ext(ucharp, ucharp);
+ erl_decode(ucharp);
+ erl_decode_buf(ucharpp);
+ erl_encode(etermp,ucharp);
+ erl_encode_buf(etermp,ucharpp);
+ erl_ext_size(ucharp);
+ erl_ext_type(ucharp);
+ erl_peek_ext(ucharp,intx);
+ erl_term_len(etermp);
+
+ erl_gethostbyname(charp);
+ erl_gethostbyaddr(charp, intx, intx);
+ erl_gethostbyname_r(charp, hostp, charp, intx, intp);
+ erl_gethostbyaddr_r(charp, intx, intx, hostp, charp, intx, intp);
+
+ erl_init_resolve();
+ erl_distversion(intx);
+
+ erl_epmd_connect(inaddrp);
+ erl_epmd_port(inaddrp, charp, intp);
+
+ charp = ERL_ATOM_PTR(etermp);
+ intx = ERL_ATOM_SIZE(etermp);
+ ucharp = ERL_BIN_PTR(etermp);
+ intx = ERL_BIN_SIZE(etermp);
+ etermp = ERL_CONS_HEAD(etermp);
+ etermp = ERL_CONS_TAIL(etermp);
+ intx = ERL_COUNT(etermp);
+ doublex= ERL_FLOAT_VALUE(etermp);
+ uintx = ERL_INT_UVALUE(etermp);
+ intx = ERL_INT_VALUE(etermp);
+ intx = ERL_IS_ATOM(etermp);
+ intx = ERL_IS_BINARY(etermp);
+ intx = ERL_IS_CONS(etermp);
+ intx = ERL_IS_EMPTY_LIST(etermp);
+ intx = ERL_IS_FLOAT(etermp);
+ intx = ERL_IS_INTEGER(etermp);
+ intx = ERL_IS_LIST(etermp);
+ intx = ERL_IS_PID(etermp);
+ intx = ERL_IS_PORT(etermp);
+ intx = ERL_IS_REF(etermp);
+ intx = ERL_IS_TUPLE(etermp);
+ intx = ERL_IS_UNSIGNED_INTEGER(etermp);
+ uchar = ERL_PID_CREATION(etermp);
+ charp = ERL_PID_NODE(etermp);
+ uintx = ERL_PID_NUMBER(etermp);
+ uintx = ERL_PID_SERIAL(etermp);
+ uchar = ERL_PORT_CREATION(etermp);
+ charp = ERL_PORT_NODE(etermp);
+ uintx = ERL_PORT_NUMBER(etermp);
+ uchar = ERL_REF_CREATION(etermp);
+ intx = ERL_REF_LEN(etermp);
+ charp = ERL_REF_NODE(etermp);
+ uintx = ERL_REF_NUMBER(etermp);
+ uintp = ERL_REF_NUMBERS(etermp);
+ etermp = ERL_TUPLE_ELEMENT(etermp,intx);
+ intx = ERL_TUPLE_SIZE(etermp);
+
+ return
+ BUFSIZ +
+ EAGAIN +
+ EHOSTUNREACH +
+ EINVAL +
+ EIO +
+ EMSGSIZE +
+ ENOMEM +
+ ERL_ATOM +
+ ERL_BINARY +
+ ERL_ERROR +
+ ERL_EXIT +
+ ERL_FLOAT +
+ ERL_INTEGER +
+ ERL_LINK +
+ ERL_LIST +
+ ERL_MSG +
+ ERL_NO_TIMEOUT +
+ ERL_PID +
+ ERL_PORT +
+ ERL_REF +
+ ERL_REG_SEND +
+ ERL_SEND +
+ ERL_SMALL_BIG +
+ ERL_TICK +
+ ERL_TIMEOUT +
+ ERL_TUPLE +
+ ERL_UNLINK +
+ ERL_U_INTEGER +
+ ERL_U_SMALL_BIG +
+ ERL_VARIABLE +
+ ETIMEDOUT +
+ MAXNODELEN +
+ MAXREGLEN;
+}
diff --git a/lib/erl_interface/src/prog/erl_start.c b/lib/erl_interface/src/prog/erl_start.c
new file mode 100644
index 0000000000..a53aab9ac7
--- /dev/null
+++ b/lib/erl_interface/src/prog/erl_start.c
@@ -0,0 +1,735 @@
+/*
+ * %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%
+ *
+
+ */
+
+/* An exception from using eidef.h, use config.h directly */
+#include "config.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef __WIN32__
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+
+#elif VXWORKS
+#include <stdio.h>
+#include <string.h>
+#include <vxWorks.h>
+#include <hostLib.h>
+#include <selectLib.h>
+#include <ifLib.h>
+#include <sockLib.h>
+#include <taskLib.h>
+#include <inetLib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <symLib.h>
+#include <sysSymTbl.h>
+#include <sysLib.h>
+#include <tickLib.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#include <a_out.h>
+
+/* #include "netdb.h" */
+#else /* other unix */
+#include <errno.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <signal.h>
+#endif
+
+#include "ei.h"
+#include "ei_resolve.h"
+#include "erl_start.h"
+
+/* FIXME is this a case a vfork can be used? */
+#if !HAVE_WORKING_VFORK
+# define vfork fork
+#endif
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+#ifndef RSH
+#define RSH "/usr/bin/rsh"
+#endif
+
+#ifndef HAVE_SOCKLEN_T
+typedef int SocklenType;
+#else
+typedef socklen_t SocklenType;
+#endif
+
+/* FIXME check errors from malloc */
+
+static struct in_addr *get_addr(const char *hostname, struct in_addr *oaddr);
+
+static int wait_for_erlang(int sockd, int magic, struct timeval *timeout);
+#if defined(VXWORKS) || defined(__WIN32__)
+static int unique_id(void);
+static unsigned long spawn_erlang_epmd(ei_cnode *ec,
+ char *alive,
+ Erl_IpAddr adr,
+ int flags,
+ char *erl_or_epmd,
+ char *args[],
+ int port,
+ int is_erlang);
+#else
+static int exec_erlang(ei_cnode *ec, char *alive, Erl_IpAddr adr, int flags,
+ char *erl, char *args[],int port);
+#endif
+/* Start an Erlang node. return value 0 indicates that node was
+ * started successfully, negative values indicate error.
+ *
+ * node - the name of the remote node to start (alivename@hostname).
+ * flags - turn on or off certain options. See erl_start.h for a list.
+ * erl - is the name of the erl script to call. If NULL, the default
+ * name "erl" will be used.
+ * args - a NULL-terminated list of strings containing
+ * additional arguments to be sent to the remote Erlang node. These
+ * strings are simply appended to the end of the command line, so any
+ * quoting of special characters, etc must be done by the caller.
+ * There may be some conflicts between some of these arguments and the
+ * default arguments hard-coded into this function, so be careful.
+ */
+int erl_start_sys(ei_cnode *ec, char *alive, Erl_IpAddr adr, int flags,
+ char *erl, char *args[])
+{
+ struct timeval timeout;
+ struct sockaddr_in addr;
+ SocklenType namelen;
+ int port;
+ int sockd = 0;
+ int one = 1;
+#if defined(VXWORKS) || defined(__WIN32__)
+ unsigned long pid = 0;
+#else
+ int pid = 0;
+#endif
+ int r = 0;
+
+ if (((sockd = socket(AF_INET, SOCK_STREAM, 0)) < 0) ||
+ (setsockopt(sockd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0)) {
+ r = ERL_SYS_ERROR;
+ goto done;
+ }
+
+ memset(&addr,0,sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_port = 0;
+
+ if (bind(sockd,(struct sockaddr *)&addr,sizeof(addr))<0) {
+ return ERL_SYS_ERROR;
+ }
+ namelen = sizeof(addr);
+ if (getsockname(sockd,(struct sockaddr *)&addr,&namelen)<0) {
+ return ERL_SYS_ERROR;
+ }
+ port = ntohs(addr.sin_port);
+
+ listen(sockd,5);
+
+#if defined(VXWORKS) || defined(__WIN32__)
+ if((pid = spawn_erlang_epmd(ec,alive,adr,flags,erl,args,port,1))
+ == 0)
+ return ERL_SYS_ERROR;
+ timeout.tv_usec = 0;
+ timeout.tv_sec = 10; /* ignoring ERL_START_TIME */
+ if((r = wait_for_erlang(sockd,unique_id(),&timeout))
+ == ERL_TIMEOUT) {
+#if defined(VXWORKS)
+ taskDelete((int) pid);
+ if(taskIdVerify((int) pid) != ERROR)
+ taskDeleteForce((int) pid);
+#else /* Windows */
+ /* Well, this is not a nice way to do it, and it does not
+ always kill the emulator, but the alternatives are few.*/
+ TerminateProcess((HANDLE) pid,1);
+#endif /* defined(VXWORKS) */
+ }
+#else /* Unix */
+ switch ((pid = fork())) {
+ case -1:
+ r = ERL_SYS_ERROR;
+ break;
+
+ case 0:
+ /* child - start the erlang node */
+ exec_erlang(ec, alive, adr, flags, erl, args, port);
+
+ /* error if reached - parent reports back to caller after timeout
+ so we just exit here */
+ exit(1);
+ break;
+
+ default:
+
+ /* parent - waits for response from Erlang node */
+ /* child pid used here as magic number */
+ timeout.tv_usec = 0;
+ timeout.tv_sec = 10; /* ignoring ERL_START_TIME */
+ if ((r = wait_for_erlang(sockd,pid,&timeout)) == ERL_TIMEOUT) {
+ /* kill child if no response */
+ kill(pid,SIGINT);
+ sleep(1);
+ if (waitpid(pid,NULL,WNOHANG) != pid) {
+ /* no luck - try harder */
+ kill(pid,SIGKILL);
+ sleep(1);
+ waitpid(pid,NULL,WNOHANG);
+ }
+ }
+
+ }
+#endif /* defined(VXWORKS) || defined(__WIN32__) */
+
+done:
+#if defined(__WIN32__)
+ if (sockd) closesocket(sockd);
+#else
+ if (sockd) close(sockd);
+#endif
+ return r;
+} /* erl_start_sys() */
+
+#if defined(VXWORKS) || defined(__WIN32__)
+#if defined(VXWORKS)
+#define DEF_ERL_COMMAND ""
+#define DEF_EPMD_COMMAND ""
+#define ERLANG_SYM "start_erl"
+#define EPMD_SYM "start_epmd"
+#define ERL_REPLY_FMT "-s erl_reply reply %s %d %d"
+#else
+#define DEF_ERL_COMMAND "erl"
+#define DEF_EPMD_COMMAND "epmd"
+#define ERL_REPLY_FMT "-s erl_reply reply \"%s\" \"%d\" \"%d\""
+#endif
+#define ERL_NAME_FMT "-noinput -name %s"
+#define ERL_SNAME_FMT "-noinput -sname %s"
+
+#define IP_ADDR_CHARS 15
+#define FORMATTED_INT_LEN 10
+
+static int unique_id(void){
+#if defined(VXWORKS)
+ return taskIdSelf();
+#else
+ return (int) GetCurrentThreadId();
+#endif
+}
+
+static int enquote_args(char **oargs, char ***qargs){
+ char **args;
+ int len;
+ int i;
+ int qwhole;
+ int extra;
+ char *ptr;
+ char *ptr2;
+
+ if(oargs == NULL){
+ *qargs = malloc(sizeof(char *));
+ **qargs = NULL;
+ return 0;
+ };
+
+ for(len=0;oargs[len] != NULL; ++len)
+ ;
+ args = malloc(sizeof(char *) * (len + 1));
+
+ for(i = 0; i < len; ++i){
+ qwhole = strchr(oargs[i],' ') != NULL;
+ extra = qwhole * 2;
+ for(ptr = oargs[i]; *ptr != '\0'; ++ptr)
+ extra += (*ptr == '"');
+ args[i] = malloc(strlen(oargs[i]) +
+ extra +
+ 1);
+ ptr2 = args[i];
+ if(qwhole)
+ *(ptr2++) = '"';
+ for(ptr = oargs[i]; *ptr != '\0'; ++ptr){
+ if(*ptr == '"')
+ *(ptr2++) = '\\';
+ *(ptr2++) = *ptr;
+ }
+ if(qwhole)
+ *(ptr2++) = '"';
+ *ptr2 = '\0';
+ }
+ args[len] = NULL;
+ *qargs = args;
+ return len;
+}
+
+static void free_args(char **args){
+ char **ptr = args;
+ while(*ptr != NULL)
+ free(*(ptr++));
+ free(args);
+}
+
+#if defined(VXWORKS)
+static FUNCPTR lookup_function(char *symname){
+ char *value;
+ SYM_TYPE type;
+ if(symFindByName(sysSymTbl,
+ symname,
+ &value,
+ &type) == ERROR /*|| type != N_TEXT*/)
+ return NULL;
+ return (FUNCPTR) value;
+}
+#endif /* defined(VXWORKS) */
+
+/* In NT and VxWorks, we cannot fork(), Erlang and Epmd gets
+ spawned by this function instead. */
+
+static unsigned long spawn_erlang_epmd(ei_cnode *ec,
+ char *alive,
+ Erl_IpAddr adr,
+ int flags,
+ char *erl_or_epmd,
+ char *args[],
+ int port,
+ int is_erlang)
+{
+#if defined(VXWORKS)
+ FUNCPTR erlfunc;
+#else /* Windows */
+ STARTUPINFO sinfo;
+ SECURITY_ATTRIBUTES sa;
+ PROCESS_INFORMATION pinfo;
+#endif
+ char *cmdbuf;
+ int cmdlen;
+ char *ptr;
+ int i;
+ int num_args;
+ char *name_format;
+ struct in_addr myaddr;
+ struct in_addr *hisaddr = (struct in_addr *)adr;
+ char iaddrbuf[IP_ADDR_CHARS + 1];
+ int ret;
+
+ if(is_erlang){
+ get_addr(ei_thishostname(ec), &myaddr);
+#if defined(VXWORKS)
+ inet_ntoa_b(myaddr, iaddrbuf);
+#else /* Windows */
+ if((ptr = inet_ntoa(myaddr)) == NULL)
+ return 0;
+ else
+ strcpy(iaddrbuf,ptr);
+#endif
+ }
+ if ((flags & ERL_START_REMOTE) ||
+ (is_erlang && (hisaddr->s_addr != myaddr.s_addr))) {
+ return 0;
+ } else {
+ num_args = enquote_args(args, &args);
+ for(cmdlen = i = 0; args[i] != NULL; ++i)
+ cmdlen += strlen(args[i]) + 1;
+#if !defined(VXWORKS)
+ /* On VxWorks, we dont actually run a command,
+ we call start_erl() */
+ if(!erl_or_epmd)
+#endif
+ erl_or_epmd = (is_erlang) ? DEF_ERL_COMMAND :
+ DEF_EPMD_COMMAND;
+ if(is_erlang){
+ name_format = (flags & ERL_START_LONG) ? ERL_NAME_FMT :
+ ERL_SNAME_FMT;
+ cmdlen +=
+ strlen(erl_or_epmd) + (*erl_or_epmd != '\0') +
+ strlen(name_format) + 1 + strlen(alive) +
+ strlen(ERL_REPLY_FMT) + 1 + strlen(iaddrbuf) +
+ 2 * FORMATTED_INT_LEN +
+ 1;
+ ptr = cmdbuf = malloc(cmdlen);
+ if(*erl_or_epmd != '\0')
+ ptr += sprintf(ptr,"%s ",erl_or_epmd);
+ ptr += sprintf(ptr, name_format,
+ alive);
+ ptr += sprintf(ptr, " " ERL_REPLY_FMT,
+ iaddrbuf, port, unique_id());
+ } else { /* epmd */
+ cmdlen += strlen(erl_or_epmd) + (*erl_or_epmd != '\0') + 1;
+ ptr = cmdbuf = malloc(cmdlen);
+ if(*erl_or_epmd != '\0')
+ ptr += sprintf(ptr,"%s ",erl_or_epmd);
+ else
+ *(ptr++) = '\0';
+ }
+ for(i= 0; args[i] != NULL; ++i){
+ *(ptr++) = ' ';
+ strcpy(ptr,args[i]);
+ ptr += strlen(args[i]);
+ }
+ free_args(args);
+ if (flags & ERL_START_VERBOSE) {
+ fprintf(stderr,"erl_call: commands are %s\n",cmdbuf);
+ }
+ /* OK, one single command line... */
+#if defined(VXWORKS)
+ erlfunc = lookup_function((is_erlang) ? ERLANG_SYM :
+ EPMD_SYM);
+ if(erlfunc == NULL){
+ if (flags & ERL_START_VERBOSE) {
+ fprintf(stderr,"erl_call: failed to find symbol %s\n",
+ (is_erlang) ? ERLANG_SYM : EPMD_SYM);
+ }
+ ret = 0;
+ } else {
+ /* Just call it, it spawns itself... */
+ ret = (unsigned long)
+ (*erlfunc)((int) cmdbuf,0,0,0,0,0,0,0,0,0);
+ if(ret == (unsigned long) ERROR)
+ ret = 0;
+ }
+#else /* Windows */
+ /* Hmmm, hidden or unhidden window??? */
+ memset(&sinfo,0,sizeof(sinfo));
+ sinfo.cb = sizeof(STARTUPINFO);
+ sinfo.dwFlags = STARTF_USESHOWWINDOW /*|
+ STARTF_USESTDHANDLES*/;
+ sinfo.wShowWindow = SW_HIDE; /* Hidden! */
+ sinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ sinfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+ sinfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = /*TRUE*/ FALSE;
+ if(!CreateProcess(
+ NULL,
+ cmdbuf,
+ &sa,
+ NULL,
+ /*TRUE*/ FALSE,
+ 0 | CREATE_NEW_CONSOLE,
+ NULL,
+ NULL,
+ &sinfo,
+ &pinfo))
+ ret = 0;
+ else
+ ret = (unsigned long) pinfo.hProcess;
+#endif
+ free(cmdbuf);
+ return ret;
+ }
+ /* NOTREACHED */
+}
+#else /* Unix */
+
+/* call this from the child process to start an erlang system. This
+ * function just builds the erlang command line and then calls it.
+ *
+ * node - the nodename for the new node
+ * flags - various options that can be set (see erl_start.h)
+ * erl - name of the erlang executable, or NULL for default ("erl")
+ * args - additional arguments to pass to erlang executable
+ * port - the port number where we wait for acknowledgment from the enode
+ *
+ * we have a potential problem if args conflicts with any of the
+ * arguments we use here.
+ */
+static int exec_erlang(ei_cnode *ec,
+ char *alive,
+ Erl_IpAddr adr,
+ int flags,
+ char *erl,
+ char *args[],
+ int port)
+{
+#if !defined(__WIN32__) && !defined(VXWORKS)
+ int fd,len,l,i;
+ char **s;
+ char *argv[4];
+ char argbuf[BUFSIZ];
+ struct in_addr myaddr;
+ struct in_addr *hisaddr = (struct in_addr *)adr;
+
+ get_addr(ei_thishostname(ec), &myaddr);
+
+ /* on this host? */
+ /* compare ip addresses, unless forced by flag setting to use rsh */
+ if ((flags & ERL_START_REMOTE) || (hisaddr->s_addr != myaddr.s_addr)) {
+ argv[0] = RSH;
+ len = strlen(inet_ntoa(*hisaddr));
+ argv[1] = malloc(len+1);
+ strcpy(argv[1],inet_ntoa(*hisaddr));
+ }
+ else {
+ /* Yes - use sh to start local Erlang */
+ argv[0] = "sh";
+ argv[1] = "-c";
+ }
+ argv[2] = argbuf;
+ argv[3] = NULL;
+
+ len = 0;
+ *argbuf=(char)0;
+
+ sprintf(argbuf,"exec %s ", (erl? erl: "erl"));
+ len = strlen(argbuf);
+
+ /* *must* be noinput or node (seems to) hang... */
+ /* long or short names? */
+ sprintf(&argbuf[len], "-noinput %s %s ",
+ ((flags & ERL_START_LONG) ? "-name" : "-sname"),
+ alive);
+ len = strlen(argbuf);
+
+ /* now make the new node report back when it's ready */
+ /* add: myip, myport and replymsg */
+ sprintf(&argbuf[len],
+ "-s erl_reply reply %s %d %d ",
+ inet_ntoa(myaddr),port,(int)getpid());
+#ifdef DEBUG
+ fprintf(stderr,"erl_call: debug %s\n",&argbuf[len]);
+#endif
+ len = strlen(argbuf);
+
+ /* additional arguments to be passed to the other system */
+ /* make sure that they will fit first */
+ for (l=0, s = args; s && *s; s++) l+= strlen(*s) + 1;
+
+ if (len + l + 1 > BUFSIZ) return ERL_BADARG;
+ else {
+ for (s = args; s && *s; s++) {
+ strcat(argbuf," ");
+ strcat(argbuf,*s);
+ }
+ len += l + 1;
+ }
+
+ if (flags & ERL_START_VERBOSE) {
+ fprintf(stderr,"erl_call: %s %s %s\n",argv[0],argv[1],argv[2]);
+ }
+
+ /* close all descriptors in child */
+ for (i=0; i<64; i++) close(i);
+
+ /* debug output to file? */
+ if (flags & ERL_START_DEBUG) {
+ char debugfile[MAXPATHLEN+1];
+ char *home=getenv("HOME");
+ sprintf(debugfile,"%s/%s.%s",home,ERL_START_LOGFILE,alive);
+ if ((fd=open(debugfile, O_WRONLY | O_CREAT | O_APPEND, 0644)) >= 0) {
+ time_t t = time(NULL);
+ dup2(fd,1);
+ dup2(fd,2);
+ fprintf(stderr,"\n\n===== Log started ======\n%s \n",ctime(&t));
+ fprintf(stderr,"erl_call: %s %s %s\n",argv[0],argv[1],argv[2]);
+ }
+ }
+
+ /* start the system */
+ execvp(argv[0], argv);
+
+ if (flags & ERL_START_DEBUG) {
+ fprintf(stderr,"erl_call: exec failed: (%d) %s %s %s\n",
+ errno,argv[0],argv[1],argv[2]);
+ }
+
+#endif
+ /* (hopefully) NOT REACHED */
+ return ERL_SYS_ERROR;
+} /* exec_erlang() */
+
+#endif /* defined(VXWORKS) || defined(WINDOWS) */
+
+#if defined(__WIN32__)
+static void gettimeofday(struct timeval *now,void *dummy){
+ SYSTEMTIME systime;
+ FILETIME ft;
+ DWORD x;
+ GetSystemTime(&systime);
+ SystemTimeToFileTime(&systime,&ft);
+ x = ft.dwLowDateTime / 10;
+ now->tv_sec = x / 1000000;
+ now->tv_usec = x % 1000000;
+}
+
+#elif defined(VXWORKS)
+static void gettimeofday(struct timeval *now, void *dummy){
+ int rate = sysClkRateGet(); /* Ticks per second */
+ unsigned long ctick = tickGet();
+ now->tv_sec = ctick / rate; /* secs since reboot */
+ now->tv_usec = ((ctick - (now->tv_sec * rate))*1000000)/rate;
+}
+#endif
+
+
+/* wait for the remote system to reply */
+/*
+ * sockd - an open socket where we expect a connection from the e-node
+ * magic - sign on message the e-node must provide for verification
+ * timeout - how long to wait before returning failure
+ *
+ * OBS: the socket is blocking, and there is a potential deadlock if we
+ * get an accept but the peer sends no data (and does not close).
+ * in normal cases the timeout will work ok however, i.e. either we
+ * never get any connection, or we get connection then close().
+ */
+static int wait_for_erlang(int sockd, int magic, struct timeval *timeout)
+{
+ struct timeval to;
+ struct timeval stop_time;
+ struct timeval now;
+ fd_set rdset;
+ int fd;
+ int n,i;
+ char buf[16];
+ struct sockaddr_in peer;
+ SocklenType len = (SocklenType) sizeof(peer);
+
+ /* determine when we should exit this function */
+ gettimeofday(&now,NULL);
+ stop_time.tv_sec = now.tv_sec + timeout->tv_sec;
+ stop_time.tv_usec = now.tv_usec + timeout->tv_usec;
+ while (stop_time.tv_usec > 1000000) {
+ stop_time.tv_sec++;
+ stop_time.tv_usec -= 1000000;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr,"erl_call: debug time is %ld.%06ld, "
+ "will timeout at %ld.%06ld\n",
+ now.tv_sec,now.tv_usec,stop_time.tv_sec,stop_time.tv_usec);
+#endif
+
+ while (1) {
+ FD_ZERO(&rdset);
+ FD_SET(sockd,&rdset);
+
+ /* adjust the timeout to (stoptime - now) */
+ gettimeofday(&now,NULL);
+ to.tv_sec = stop_time.tv_sec - now.tv_sec;
+ to.tv_usec = stop_time.tv_usec - now.tv_usec;
+ while ((to.tv_usec <= 0) && (to.tv_sec >= 0)) {
+ to.tv_usec += 1000000;
+ to.tv_sec--;
+ }
+ if (to.tv_sec < 0) return ERL_TIMEOUT;
+
+#ifdef DEBUG
+ fprintf(stderr,"erl_call: debug remaining to timeout: %ld.%06ld\n",
+ to.tv_sec,to.tv_usec);
+#endif
+ switch ((i = select(sockd+1,&rdset,NULL,NULL,&to))) {
+ case -1:
+ return ERL_SYS_ERROR;
+ break;
+
+ case 0: /* timeout */
+#ifdef DEBUG
+ gettimeofday(&now,NULL);
+ fprintf(stderr,"erl_call: debug timed out at %ld.%06ld\n",
+ now.tv_sec,now.tv_usec);
+#endif
+ return ERL_TIMEOUT;
+ break;
+
+ default: /* ready descriptors */
+#ifdef DEBUG
+ gettimeofday(&now,NULL);
+ fprintf(stderr,"erl_call: debug got select at %ld.%06ld\n",
+ now.tv_sec,now.tv_usec);
+#endif
+ if (FD_ISSET(sockd,&rdset)) {
+ if ((fd = accept(sockd,(struct sockaddr *)&peer,&len)) < 0)
+ return ERL_SYS_ERROR;
+
+ /* now get sign-on message and terminate it */
+#if defined(__WIN32__)
+ if ((n=recv(fd,buf,16,0)) >= 0) buf[n]=0x0;
+ closesocket(fd);
+#else
+ if ((n=read(fd,buf,16)) >= 0) buf[n]=0x0;
+ close(fd);
+#endif
+#ifdef DEBUG
+ fprintf(stderr,"erl_call: debug got %d, expected %d\n",
+ atoi(buf),magic);
+#endif
+
+ if (atoi(buf) == magic) return 0; /* success */
+ } /* if FD_SET */
+ } /* switch */
+ } /* while */
+
+ /* unreached? */
+ return ERL_SYS_ERROR;
+} /* wait_for_erlang() */
+
+
+static struct in_addr *get_addr(const char *hostname, struct in_addr *oaddr)
+{
+ struct hostent *hp;
+
+#if !defined (__WIN32__)
+ char buf[1024];
+ struct hostent host;
+ int herror;
+
+ hp = ei_gethostbyname_r(hostname,&host,buf,1024,&herror);
+#else
+ hp = ei_gethostbyname(hostname);
+#endif
+
+ if (hp) {
+ memmove(oaddr,hp->h_addr_list[0],sizeof(*oaddr));
+ return oaddr;
+ }
+ return NULL;
+}
diff --git a/lib/erl_interface/src/prog/erl_start.h b/lib/erl_interface/src/prog/erl_start.h
new file mode 100644
index 0000000000..05f34864a7
--- /dev/null
+++ b/lib/erl_interface/src/prog/erl_start.h
@@ -0,0 +1,46 @@
+/*
+ * %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%
+ *
+
+ */
+#ifndef _ERL_START_H
+#define _ERL_START_H
+
+#define ERL_START_MSG "gurka" /* make something up */
+#define ERL_START_TIME 10000 /* wait this long (ms) */
+#define ERL_START_LOGFILE ".erl_start.out" /* basename of logfile */
+
+/* flags used by erl_connect and erl_xconnect */
+#define ERL_START_ENODE 0x0001
+#define ERL_START_EPMD 0x0002
+#define ERL_START_LONG 0x0004
+#define ERL_START_COOKIE 0x0008
+#define ERL_START_DEBUG 0x0010
+#define ERL_START_VERBOSE 0x0020
+#define ERL_START_REMOTE 0x0040
+
+/* error return values */
+#define ERL_S_TIMEOUT -51 /* a timeout occurred */
+#define ERL_BADARG -52 /* an argument contained an incorrect value */
+#define ERL_SYS_ERROR -99 /* a system error occurred (check errno) */
+
+/* start an erlang system */
+int erl_start_sys(ei_cnode *ec, char *alive, Erl_IpAddr addr, int flags,
+ char *erl, char *add_args[]);
+
+#endif /* _ERL_START_H */
diff --git a/lib/erl_interface/src/registry/hash.h b/lib/erl_interface/src/registry/hash.h
new file mode 100644
index 0000000000..3886e8664b
--- /dev/null
+++ b/lib/erl_interface/src/registry/hash.h
@@ -0,0 +1,47 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ *
+
+ */
+#ifndef _HASH_H
+#define _HASH_H
+
+#include <stdio.h>
+
+#include "ei.h" /* We need our types there */
+
+#define ei_hash_size(tab) ((tab)->size)
+#define ei_hash_count(tab) ((tab)->count)
+
+#define ALIGN_QUAD 0x7
+#define ei_align(size) while (((unsigned)size) & ALIGN_QUAD) (size)++
+
+int ei_isprime(int n);
+int ei_dohash(const char *key);
+void *ei_hash_lookup(ei_hash *tab, const char *key);
+const char *ei_hash_rlookup(ei_hash *tab, const void *value);
+int ei_hash_foreach(ei_hash *tab, int (*f)(const char *key, const void *value));
+void *ei_hash_insert(ei_hash *tab, const char *key, const void *value);
+void *ei_hash_remove(ei_hash *tab, const char *key);
+ei_hash *ei_hash_newtab(int tabsize);
+ei_hash *ei_hash_resize(ei_hash *oldtab, int newsize);
+int ei_hash_freetab(ei_hash *tab, void (*f)(void *));
+void ei_hash_stats(ei_hash *tab, FILE *out);
+void ei_hash_bfree(ei_hash *tab, ei_bucket *b);
+
+#endif /* _HASH_H */
diff --git a/lib/erl_interface/src/registry/hash_dohash.c b/lib/erl_interface/src/registry/hash_dohash.c
new file mode 100644
index 0000000000..f672dce9b3
--- /dev/null
+++ b/lib/erl_interface/src/registry/hash_dohash.c
@@ -0,0 +1,45 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include "hash.h"
+
+/* This is hashpjw, from the dragon book */
+/* Note that this function is only used as a default hash function.
+ * All calls are made through the hash pointer in the tab structure.
+ * The only place this function is explicitly referenced is in
+ * hash_newtab(); Users can use hash_setfunc() to change the hash function.
+ */
+int ei_dohash(const char *key)
+{
+ const char *s;
+ unsigned h = 0;
+ unsigned g;
+
+ for (s=key; *s; s++) {
+ h = (h << 4) + *s;
+ if ((g = (h & 0xf0000000))) { /* assumes 32-bit int */
+ h = h^(g >> 24);
+ h = h^g;
+ }
+ }
+ return h;
+}
+
+
diff --git a/lib/erl_interface/src/registry/hash_foreach.c b/lib/erl_interface/src/registry/hash_foreach.c
new file mode 100644
index 0000000000..77afc7ade1
--- /dev/null
+++ b/lib/erl_interface/src/registry/hash_foreach.c
@@ -0,0 +1,44 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include "hash.h"
+
+/* perform f(key,value) on each key-value pair in the table.
+ * hash_foreach() will traverse the table until the end is reached or
+ * until f() returns a non-zero value, whichever comes first. The
+ * return value from f() will be returned to the caller, or 0 if the
+ * entire table was traversed.
+ */
+int ei_hash_foreach(ei_hash *tab, int (*f)(const char *key, const void *value))
+{
+ ei_bucket *b;
+ int i;
+ int r;
+
+ for (i=0; i<tab->size; i++) {
+ b=tab->tab[i];
+ while (b) {
+ if (f && (r=f(b->key,b->value))) return r;
+ b = b->next;
+ }
+ }
+ return 0;
+}
+
diff --git a/lib/erl_interface/src/registry/hash_freetab.c b/lib/erl_interface/src/registry/hash_freetab.c
new file mode 100644
index 0000000000..cd428e55cf
--- /dev/null
+++ b/lib/erl_interface/src/registry/hash_freetab.c
@@ -0,0 +1,58 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include "hash.h"
+
+/* remove all the key-values from a table. The
+ * values are removed with
+ * the user-provided function f.
+ */
+int ei_hash_freetab(ei_hash *tab, void (*f)(void *))
+{
+ ei_bucket *b, *next;
+ int i;
+
+ for (i=0; i<tab->size; i++) {
+ b=tab->tab[i];
+ while (b) {
+ next = b->next;
+
+ if (f) f((void *)b->value);
+
+ /* no point in saving these buckets on freelist */
+ free(b);
+ b = next;
+ }
+ }
+
+ /* remove the freelist */
+ b = tab->freelist;
+ while (b) {
+ next = b->next;
+ free(b);
+ b = next;
+ }
+
+ /* remove the table */
+ free(tab);
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/registry/hash_insert.c b/lib/erl_interface/src/registry/hash_insert.c
new file mode 100644
index 0000000000..dbe76282ae
--- /dev/null
+++ b/lib/erl_interface/src/registry/hash_insert.c
@@ -0,0 +1,108 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "hash.h"
+
+/* this function returns a bucket - from the freelist if one was found
+ * there, or from malloc(). Only "small" buckets, i.e. those whose
+ * keys are short enough to be stored in the bucket itself, are saved
+ * on the freelist.
+ */
+static ei_bucket *ei_hash_bmalloc(ei_hash *tab)
+{
+ ei_bucket *new;
+
+ if (tab->freelist) {
+ new = tab->freelist;
+ tab->freelist = new->next;
+ /* fprintf(stderr,"getting bucket from freelist\n"); */
+ }
+ else {
+ new = malloc(sizeof(*new));
+ /* fprintf(stderr,"allocating new (small) bucket\n"); */
+ }
+
+ return new;
+}
+
+/* insert a new key-value pair. The old value (if any) is returned. If
+ * the malloc fails the function returns NULL. This is potentially a
+ * problem since the function returns the same thing when malloc fails
+ * as when a item is inserted that did not previously exist in the
+ * table. */
+void *ei_hash_insert(ei_hash *tab, const char *key, const void *value)
+{
+ const void *oldval=NULL;
+ ei_bucket *b=NULL;
+ int h, rh;
+
+ rh = tab->hash(key);
+ h = rh % tab->size;
+
+ b=tab->tab[h];
+ while (b) {
+ if ((rh == b->rawhash) && (!strcmp(key,b->key)))
+ break;
+ b=b->next;
+ }
+
+ if (b) {
+ /* replace existing value, return old value */
+ oldval = b->value;
+ b->value = value;
+ }
+ else {
+ int keylen = strlen(key);
+
+ /* this element is new */
+ if (keylen < EI_SMALLKEY) {
+ /* short keys stored directly in bucket */
+ /* try to get bucket from freelist */
+ if ((b = ei_hash_bmalloc(tab)) == NULL) return NULL;
+ b->key = b->keybuf;
+ }
+ else {
+ /* for longer keys we allocate space */
+ int keypos=sizeof(*b);
+
+ ei_align(keypos);
+ if ((b = malloc(keypos+keylen+1)) == NULL) return NULL;
+ b->key = (char *)b + keypos;
+ /* fprintf(stderr,"allocating new (large) bucket\n"); */
+ }
+
+ /* fill in the blanks */
+ b->rawhash = rh;
+ strcpy((char *)b->key,key);
+ b->value = value;
+
+ /* some statistiscs */
+ if (!tab->tab[h]) tab->npos++;
+ tab->nelem++;
+
+ /* link in the new element */
+ b->next = tab->tab[h];
+ tab->tab[h] = b;
+ }
+ return (void *)oldval;
+}
+
diff --git a/lib/erl_interface/src/registry/hash_isprime.c b/lib/erl_interface/src/registry/hash_isprime.c
new file mode 100644
index 0000000000..cdef2591ab
--- /dev/null
+++ b/lib/erl_interface/src/registry/hash_isprime.c
@@ -0,0 +1,57 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include "hash.h"
+
+/* this is a general prime factoring function
+ * we get one prime factor each time we call it
+ * we only use it here to determine if n is prime,
+ * by checking if factor(n) == n .
+ */
+static int factor(int n)
+{
+ /* FIXME problem for threaded?! */
+ static int a[] = { 0, 4, 1, 2, 0, 2 };
+ static int m = 0;
+ static int d = 0;
+
+ if (n) {
+ m = n;
+ d = 2;
+ }
+
+ while ((d*d) <= m) {
+ if (!(m%d)) {
+ m /= d;
+ return d;
+ }
+ d += a[d%6];
+ }
+ n = m;
+ m = 0;
+
+ return n;
+}
+
+/* true if n prime */
+int ei_isprime(int n)
+{
+ return (n == factor(n));
+}
diff --git a/lib/erl_interface/src/registry/hash_lookup.c b/lib/erl_interface/src/registry/hash_lookup.c
new file mode 100644
index 0000000000..0a466cc519
--- /dev/null
+++ b/lib/erl_interface/src/registry/hash_lookup.c
@@ -0,0 +1,42 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "hash.h"
+
+void *ei_hash_lookup(ei_hash *tab, const char *key)
+{
+ int h, rh;
+ ei_bucket *b=NULL;
+
+ rh = tab->hash(key);
+ h = rh % tab->size;
+
+ b=tab->tab[h];
+ while (b) {
+ if ((rh == b->rawhash) && (!strcmp(key,b->key)))
+ return (void *)b->value;
+ b=b->next;
+ }
+ return NULL;
+}
+
+
diff --git a/lib/erl_interface/src/registry/hash_newtab.c b/lib/erl_interface/src/registry/hash_newtab.c
new file mode 100644
index 0000000000..b900de1f69
--- /dev/null
+++ b/lib/erl_interface/src/registry/hash_newtab.c
@@ -0,0 +1,52 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "hash.h"
+
+ei_hash *ei_hash_newtab(int tabsize)
+{
+ ei_hash *tab=NULL;
+ int bucketpos=sizeof(*tab);
+
+ /* make sure size is odd, then increase until prime */
+ tabsize |= 0x1;
+ while (!ei_isprime(tabsize)) tabsize +=2;
+
+ /* we will only do one malloc, so "sizeof(*tab)"
+ * must be adjusted to align tab->tab properly
+ */
+ ei_align(bucketpos);
+
+ /* single malloc, then fill in all fields */
+ if ((tab = malloc(bucketpos + (tabsize * (sizeof(*(tab->tab))))))) {
+ tab->tab = (ei_bucket **)((char *)tab + bucketpos);
+ memset(tab->tab,0,tabsize*sizeof(*(tab->tab)));
+ tab->hash = ei_dohash;
+ tab->size = tabsize;
+ tab->npos = 0;
+ tab->nelem = 0;
+ tab->freelist = NULL;
+ }
+
+ return tab;
+}
+
diff --git a/lib/erl_interface/src/registry/hash_remove.c b/lib/erl_interface/src/registry/hash_remove.c
new file mode 100644
index 0000000000..cebe00da1c
--- /dev/null
+++ b/lib/erl_interface/src/registry/hash_remove.c
@@ -0,0 +1,87 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "hash.h"
+
+/* free a hash bucket. If the bucket contained a long key (more that
+ * EI_SMALLKEY) the bucket is thrown away (really freed). If the
+ * bucket contained a short key, then it can be saved on the freelist
+ * for later use. Buckets with short keys have (key == keybuf).
+ */
+void ei_hash_bfree(ei_hash *tab, ei_bucket *b)
+{
+ if (!b) return;
+
+ /* we throw away buckets with long keys (i.e. non-standard buckets) */
+ if (b->key != b->keybuf) {
+ /* fprintf(stderr,"freeing bucket with long key (%s)\n",b->key); */
+ free(b);
+ }
+
+ else {
+ /* others we save on (tab-local) freelist */
+ /* fprintf(stderr,"saving bucket with short key (%s)\n",b->key); */
+ b->next = tab->freelist;
+ tab->freelist = b;
+ }
+
+ return;
+}
+
+void *ei_hash_remove(ei_hash *tab, const char *key)
+{
+ ei_bucket *b=NULL, *tmp=NULL;
+ const void *oldval=NULL;
+ int h, rh;
+
+ rh = tab->hash(key);
+ h = rh % tab->size;
+
+ /* is it in the first position? */
+ if ((b=tab->tab[h])) {
+ if ((rh == b->rawhash) && (!strcmp(key,b->key))) {
+ tab->tab[h] = b->next;
+ oldval = b->value;
+ ei_hash_bfree(tab,b);
+
+ tab->nelem--;
+ if (!tab->tab[h]) tab->npos--;
+ }
+ else {
+ /* is it later in the chain? */
+ while (b->next) {
+ if ((rh == b->next->rawhash) && (!strcmp(key,b->next->key))) {
+ tmp = b->next;
+ b->next = tmp->next;
+ oldval = tmp->value;
+ ei_hash_bfree(tab,tmp);
+
+ tab->nelem--;
+ break;
+ }
+ b=b->next;
+ }
+ }
+ }
+ return (void *)oldval;
+}
+
diff --git a/lib/erl_interface/src/registry/hash_resize.c b/lib/erl_interface/src/registry/hash_resize.c
new file mode 100644
index 0000000000..9c34a0d41c
--- /dev/null
+++ b/lib/erl_interface/src/registry/hash_resize.c
@@ -0,0 +1,67 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include "hash.h"
+
+/* move the elements from oldtab to a new table newsize. The old table
+ * is freed and the caller should discard the pointer. On failure
+ * (i.e. if malloc fails) return the old table and do nothing.
+*/
+ei_hash *ei_hash_resize(ei_hash *oldtab, int newsize)
+{
+ ei_hash *newtab=NULL;
+ ei_bucket *b, *next;
+ int i,h;
+
+ /* make sure size is odd, then increase until prime */
+ newsize |= 0x1;
+ while (!ei_isprime(newsize)) newsize +=2;
+
+ if (newsize == oldtab->size) return oldtab;
+
+ /* make a new table */
+ if (!(newtab = ei_hash_newtab(newsize))) return oldtab;
+ newtab->hash = oldtab->hash;
+
+ /* move the buckets, rehashing */
+ /* note that this will reverse the order of any chains */
+ for (i=0; i<oldtab->size; i++) {
+ b=oldtab->tab[i];
+ while (b) {
+ next = b->next;
+ h = b->rawhash % newtab->size;
+ b->next=newtab->tab[h];
+ if (!newtab->tab[h]) newtab->npos++;
+ newtab->tab[h]=b;
+ b = next;
+ }
+ }
+ /* the new table has the same number of elements as the old one */
+ newtab->nelem = oldtab->nelem;
+
+ /* the new table takes over the freelist from the old one */
+ newtab->freelist = oldtab->freelist;
+
+ /* now it's safe to remove the old table */
+ free(oldtab);
+
+ return newtab;
+}
diff --git a/lib/erl_interface/src/registry/hash_rlookup.c b/lib/erl_interface/src/registry/hash_rlookup.c
new file mode 100644
index 0000000000..5d401555d8
--- /dev/null
+++ b/lib/erl_interface/src/registry/hash_rlookup.c
@@ -0,0 +1,43 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include "hash.h"
+
+/* this function does a reverse lookup and returns the first key whose
+ * value matches value. This operation may be lengthy! Also, there is
+ * no guarantee that the *values* are unique in the hash table, so the
+ * returned key might not be the one you expect.
+ */
+const char *ei_hash_rlookup(ei_hash *tab, const void *value)
+{
+ ei_bucket *b;
+ int i;
+
+ for (i=0; i<tab->size; i++) {
+ b=tab->tab[i];
+ while (b) {
+ if (b->value == value) return b->key;
+ b = b->next;
+ }
+ }
+ return NULL;
+}
+
diff --git a/lib/erl_interface/src/registry/reg.h b/lib/erl_interface/src/registry/reg.h
new file mode 100644
index 0000000000..cb7685506c
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg.h
@@ -0,0 +1,46 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ *
+
+ */
+#ifndef _REG_H
+#define _REG_H
+
+#include "ei.h" /* Our public defines, types and declarations */
+#include "hash.h"
+
+#define EI_MNESIA_MODULE "mnesia_registry"
+
+#define EI_MNESIA_DUMP "start_dump"
+#define EI_MNESIA_WRITE "write"
+#define EI_MNESIA_DELETE "delete"
+#define EI_MNESIA_COMMIT "commit"
+
+#define EI_MNESIA_RESTORE "start_restore"
+#define EI_MNESIA_SEND "send_records"
+#define EI_MNESIA_RECV "restore"
+#define EI_MNESIA_SIZE "size"
+
+#define EI_REG_TYPEMASK 0xf8 /* all but lowest bits */
+#define ei_reg_typeof(r) (r->attr & EI_REG_TYPEMASK)
+
+ei_reg_obj *ei_reg_make(ei_reg *reg, int attr);
+
+void ei_reg_free(ei_reg *reg, ei_reg_obj *obj);
+
+#endif /* _REG_H */
diff --git a/lib/erl_interface/src/registry/reg_close.c b/lib/erl_interface/src/registry/reg_close.c
new file mode 100644
index 0000000000..b699e59ac8
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_close.c
@@ -0,0 +1,68 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include "reg.h"
+
+/* really remove an object (help function to hash_freetab) */
+static void obj_free(void *p)
+{
+ ei_reg_obj *obj = p;
+
+ if (obj) {
+ switch (ei_reg_typeof(obj)) {
+ case EI_STR:
+ free(obj->val.s);
+ break;
+
+ case EI_BIN:
+ free(obj->val.p);
+ break;
+ }
+
+ /* really remove the inode (don't use freelist here) */
+ free(obj);
+ }
+ return;
+}
+
+/* close an open registry */
+int ei_reg_close(ei_reg *reg)
+{
+ ei_reg_obj *obj, *next;
+
+ if (!reg) return -1; /* return EI_BADARG; */
+
+ /* remove hash_table */
+ ei_hash_freetab(reg->tab,obj_free);
+
+ /* remove freelist */
+ obj = reg->freelist;
+ while (obj) {
+ next = obj->next;
+ free(obj);
+ obj = next;
+ }
+
+ /* remove registry */
+ free(reg);
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/registry/reg_delete.c b/lib/erl_interface/src/registry/reg_delete.c
new file mode 100644
index 0000000000..8e84e205ee
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_delete.c
@@ -0,0 +1,36 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include "reg.h"
+
+int ei_reg_delete(ei_reg *reg, const char *key)
+{
+ ei_hash *tab;
+ ei_reg_obj *obj;
+
+ if (!key || !reg) return -1; /* return EI_BADARG; */
+ tab = reg->tab;
+ if (!(obj = ei_hash_lookup(tab,key))) return -1; /* return EI_NOTFOUND; */
+
+ /* just mark the object deleted */
+ obj->attr |= (EI_DELET | EI_DIRTY);
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/registry/reg_dirty.c b/lib/erl_interface/src/registry/reg_dirty.c
new file mode 100644
index 0000000000..730b4445c6
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_dirty.c
@@ -0,0 +1,36 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include "reg.h"
+
+int ei_reg_markdirty(ei_reg *reg, const char *key)
+{
+ ei_hash *tab;
+ ei_reg_obj *obj;
+
+ if (!key || !reg) return -1; /* EI_BADARG; */
+ tab = reg->tab;
+ if (!(obj = ei_hash_lookup(tab,key))) return -1; /* return EI_NOTFOUND; */
+
+ /* just mark the object dirty */
+ obj->attr |= EI_DIRTY;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/registry/reg_dump.c b/lib/erl_interface/src/registry/reg_dump.c
new file mode 100644
index 0000000000..50a6949177
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_dump.c
@@ -0,0 +1,321 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "reg.h"
+#include "eisend.h"
+#include "eirecv.h"
+#include "ei_connect_int.h"
+
+static int mn_start_dump(int fd, const erlang_pid *self,
+ erlang_pid *mnesia, const char *mntab)
+{
+ char buf[EISMALLBUF];
+ char *bufp = buf;
+ char tmpbuf[64];
+ int index = 0;
+ erlang_msg msg;
+ int type;
+ int arity;
+ int version;
+ int msglen;
+ int i;
+ int needlink;
+ int needpid;
+
+ /* set up rpc arguments */
+ /* { PidFrom, { call, Mod, Fun, Args, user }} */
+ ei_encode_version(buf,&index);
+ ei_encode_tuple_header(buf,&index,2);
+ ei_encode_pid(buf,&index,self); /* PidFrom */
+ ei_encode_tuple_header(buf,&index,5);
+ ei_encode_atom(buf,&index,"call"); /* call */
+ ei_encode_atom(buf,&index,EI_MNESIA_MODULE); /* Mod */
+ ei_encode_atom(buf,&index,EI_MNESIA_DUMP); /* Fun */
+ ei_encode_list_header(buf,&index,2); /* Args: [ table, self() ] */
+ ei_encode_atom(buf,&index,mntab);
+ ei_encode_pid(buf,&index,self);
+ ei_encode_empty_list(buf,&index);
+ ei_encode_atom(buf,&index,"user"); /* user */
+
+ /* make the rpc call */
+ if (ei_send_reg_encoded(fd,self,"rex",buf,index)) return -1;
+
+ /* get the reply: expect link and pid (not sure which will come first though) */
+ needlink = needpid = 1;
+ while (needlink || needpid) {
+ /* get message */
+ while (1) {
+ index = EISMALLBUF;
+ if (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue;
+ else break;
+ }
+
+ switch (i) {
+ case ERL_LINK:
+ /* got link */
+ if (!needlink) return -1;
+ needlink = 0;
+ break;
+
+ case ERL_SEND:
+ /* got message - does it contain a pid? */
+ if (!needpid) return -1;
+ else {
+ /* expecting { rex, <pid> } */
+ index = 0;
+ if (ei_decode_version(buf,&index,&version)
+ || ei_decode_tuple_header(buf,&index,&arity)
+ || (arity != 2)
+ || ei_decode_atom(buf,&index,tmpbuf)
+ || strcmp(tmpbuf,"rex")
+ || ei_get_type_internal(buf,&index,&type,&arity)
+ || (type != ERL_PID_EXT))
+ return -1; /* bad response from other side */
+
+ if (ei_decode_pid(buf,&index,mnesia)) return -1;
+
+ /* got pid */
+ needpid = 0;
+ }
+ break;
+
+ default:
+ return -1; /* wasn't link or pid */
+ }
+ }
+ return 0;
+}
+
+static int mn_send_commit(int fd, erlang_pid *mnesia, erlang_pid *self)
+{
+ char buf[EISMALLBUF];
+ char *bufp=buf;
+ char string[256];
+ int index = 0;
+ int version,arity;
+ int msglen;
+ erlang_msg msg;
+ int i;
+
+ /* set up commit message { commit, self() } */
+ ei_encode_version(buf,&index);
+ ei_encode_tuple_header(buf,&index,2);
+ ei_encode_atom(buf,&index,EI_MNESIA_COMMIT);
+ ei_encode_pid(buf,&index,self);
+
+ /* send it */
+ if (ei_send_encoded(fd,mnesia,buf,index)) return -1;
+
+ /* get reply */
+ while (1) {
+ index = EISMALLBUF;
+ if (!(i=ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) continue;
+ else if (i < 0) return -1;
+ else break;
+ }
+
+ if (i == ERL_SEND) {
+ index = 0;
+ if (ei_decode_version(buf,&index,&version)
+ || ei_decode_tuple_header(buf,&index,&arity)
+ || ei_decode_atom(buf,&index,string))
+ return -1;
+
+ if (!strcmp(string,"ok")) return 0;
+ }
+ /* wrong message type */
+ return -1;
+}
+
+static int mn_send_delete(int fd, erlang_pid *mnesia, const char *key)
+{
+ char sbuf[EISMALLBUF];
+ char *dbuf = NULL;
+ char *msgbuf;
+ int index = 0;
+ int len = strlen(key) + 32; /* 32 is a slight overestimate */
+
+ if (len > EISMALLBUF)
+ if (!(dbuf = malloc(index)))
+ return -1;
+ msgbuf = (dbuf ? dbuf : sbuf);
+
+ /* set up delete message { delete, Key } */
+ ei_encode_version(msgbuf,&index);
+ ei_encode_tuple_header(msgbuf,&index,2);
+ ei_encode_atom(msgbuf,&index,EI_MNESIA_DELETE);
+ ei_encode_string(msgbuf,&index,key);
+
+ /* send it */
+ if (ei_send_encoded(fd,mnesia,msgbuf,index)) {
+ if (dbuf) free(dbuf);
+ return -1;
+ }
+
+ if (dbuf) free(dbuf);
+ return 0;
+}
+
+static int mn_send_write(int fd, erlang_pid *mnesia, const char *key, ei_reg_obj *obj)
+{
+ char sbuf[EISMALLBUF];
+ char *dbuf = NULL;
+ char *msgbuf;
+ int index = 0;
+ int keylen = strlen(key) + 1;
+ int len = 32 + keylen + obj->size;
+
+ if (len > EISMALLBUF)
+ if (!(dbuf = malloc(index)))
+ return -1;
+ msgbuf = (dbuf ? dbuf : sbuf);
+
+ ei_encode_version(msgbuf,&index);
+ ei_encode_tuple_header(msgbuf,&index,6);
+ ei_encode_atom(msgbuf,&index,EI_MNESIA_WRITE);
+ ei_encode_string(msgbuf,&index,key);
+ ei_encode_long(msgbuf,&index,keylen);
+ ei_encode_long(msgbuf,&index,obj->attr);
+ ei_encode_long(msgbuf,&index,obj->size);
+
+ switch (ei_reg_typeof(obj)) {
+ case EI_INT:
+ ei_encode_long(msgbuf,&index,obj->val.i);
+ break;
+ case EI_FLT:
+ ei_encode_double(msgbuf,&index,obj->val.f);
+ break;
+ case EI_STR:
+ if (obj->size > 0) ei_encode_string(msgbuf,&index,obj->val.s);
+ else ei_encode_long(msgbuf,&index, (long)NULL); /* just the NULL pointer */
+ break;
+ case EI_BIN:
+ if (obj->size > 0) ei_encode_binary(msgbuf,&index,obj->val.p,obj->size);
+ else ei_encode_long(msgbuf,&index,(long)(obj->val.p)); /* just the pointer */
+ break;
+ default:
+ return -1;
+ }
+
+ /* send it */
+ if (ei_send_encoded(fd,mnesia,msgbuf,index)) {
+ if (dbuf) free(dbuf);
+ return -1;
+ }
+
+ if (dbuf) free(dbuf);
+ return 0;
+}
+
+static int mn_get_unlink(int fd)
+{
+ erlang_msg msg;
+ char buf[EISMALLBUF];
+ char *bufp=buf;
+ int index;
+ int msglen;
+
+ /* wait for unlink or exit */
+ while (1) {
+ index = EISMALLBUF;
+ switch (ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0)) {
+ case 0: continue;
+ case ERL_UNLINK: return 0;
+ default: return -1;
+ }
+ }
+ return 0;
+}
+
+/* dump to backup */
+/* fd is open connection to erlang node */
+int ei_reg_dump(int fd, ei_reg *reg, const char *mntab, int flags)
+{
+ ei_hash *tab;
+ erlang_pid self;
+ erlang_pid mnesia;
+ ei_bucket *b;
+ ei_reg_obj *obj;
+ const char *key;
+ ei_cnode *ec;
+ int i;
+
+ if (!reg || !mntab) return -1; /* return EI_BADARG; */
+ tab = reg->tab;
+
+ /* make a self pid */
+
+ if ((ec = ei_fd_to_cnode(fd)) == NULL) {
+ return -1;
+ }
+ strcpy(self.node,ei_thisnodename(ec));
+ self.num = fd;
+ self.serial = 0;
+ self.creation = ei_thiscreation(ec);
+
+ if (mn_start_dump(fd,&self,&mnesia,mntab)) return -1;
+
+ /* traverse the table, passing objects to mnesia */
+ for (i=0; i<tab->size; i++) {
+ b=tab->tab[i];
+ while (b) {
+ obj = (ei_reg_obj*)(b->value); /* cast to eliminate 'const' warning */
+ key = b->key;
+
+ if ((flags & EI_FORCE) || (obj->attr & EI_DIRTY)) {
+ if (obj->attr & EI_DELET) {
+ if (mn_send_delete(fd,&mnesia,key)) {
+ ei_send_exit(fd,&self,&mnesia,"delete failed");
+ return -1;
+ }
+ }
+ else {
+ if (mn_send_write(fd,&mnesia,key,obj)) {
+ ei_send_exit(fd,&self,&mnesia,"update failed");
+ return -1;
+ }
+ }
+ }
+ b = b->next;
+ }
+ }
+
+ /* end the transaction */
+ if (mn_send_commit(fd,&mnesia,&self)) {
+ ei_send_exit(fd,&self,&mnesia,"commit failed");
+ return -1;
+ }
+
+ /* wait for unlink */
+ if (mn_get_unlink(fd)) return -1;
+
+ /* this point only reached if all went ok so far... */
+
+ /* now remove all deleted objects, unless the caller asked us not to */
+ if (!(flags & EI_NOPURGE)) ei_reg_purge(reg);
+
+ /* success */
+ return 0;
+
+}
diff --git a/lib/erl_interface/src/registry/reg_free.c b/lib/erl_interface/src/registry/reg_free.c
new file mode 100644
index 0000000000..e3245577a5
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_free.c
@@ -0,0 +1,47 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include "reg.h"
+
+/* free a registry object (inode) on the freelist. The "value"
+ * contained by the object is removed.
+ */
+void ei_reg_free(ei_reg *reg, ei_reg_obj *obj)
+{
+ /* free the value part */
+ switch (ei_reg_typeof(obj)) {
+ case EI_STR:
+ free(obj->val.s);
+ break;
+
+ case EI_BIN:
+ free(obj->val.p);
+ break;
+ }
+
+ /* fprintf(stderr,"%s:%d: saving %p on freelist\n",__FILE__,__LINE__,obj);*/
+
+ /* save the rest on the freelist */
+ obj->next = reg->freelist;
+ reg->freelist = obj;
+
+ return;
+}
diff --git a/lib/erl_interface/src/registry/reg_get.c b/lib/erl_interface/src/registry/reg_get.c
new file mode 100644
index 0000000000..d1909b3fed
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_get.c
@@ -0,0 +1,94 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#ifdef VXWORKS
+#include <vxWorks.h>
+#endif
+
+#include <stdarg.h>
+#include "reg.h"
+
+/* this is the general "get" function. Values are copied into a buffer
+ * provided by the caller, and the return value indicates success or
+ * failure. This function can get all types except directorys. The user
+ * must specify the type of data he is expecting, or 0 if he doesn't
+ * care. On success, the data type is returned. If the requested data
+ * type does not match the data found, EI_TYPE is returned.
+ */
+int ei_reg_getval(ei_reg *reg, const char *key, int flags, ...)
+{
+ ei_hash *tab;
+ ei_reg_obj *obj=NULL;
+ va_list ap;
+ int rval;
+ int objtype;
+
+ if (!key || !reg) return -1; /* return EI_BADARG; */
+ tab = reg->tab;
+ if (!(obj=ei_hash_lookup(tab,key))) return -1; /* return EI_NOTFOUND; */
+ if (obj->attr & EI_DELET) return -1; /* return EI_NOTFOUND; */
+
+ /* if type was specified then it must match object */
+ objtype = ei_reg_typeof(obj);
+ if (flags && (flags != objtype)) return -1; /* return EI_TYPE; */
+
+ va_start(ap,flags);
+
+ switch ((rval = objtype)) {
+ case EI_INT: {
+ long *ip;
+
+ if (!(ip = va_arg(ap,long*))) rval = -1; /* EI_BADARG; */
+ else *ip = obj->val.i;
+ break;
+ }
+ case EI_FLT: {
+ double *fp;
+
+ if (!(fp = va_arg(ap,double*))) rval = -1; /* EI_BADARG; */
+ else *fp = obj->val.f;
+ break;
+ }
+ case EI_STR: {
+ char **sp;
+
+ if (!(sp = va_arg(ap,char**))) rval = -1; /* EI_BADARG; */
+ else *sp = obj->val.s;
+ break;
+ }
+ case EI_BIN: {
+ void **pp;
+ int *size;
+
+ if (!(pp = va_arg(ap,void**))) rval = -1; /* EI_BADARG; */
+ else *pp = obj->val.p;
+ if ((size=va_arg(ap,int*))) *size=obj->size;
+ break;
+ }
+ default:
+ /* can't (should never) happen */
+ rval = -1;
+ /* rval = EI_UNKNOWN; */
+ }
+
+ /* clean up & return */
+ va_end(ap);
+ return rval;
+}
diff --git a/lib/erl_interface/src/registry/reg_getf.c b/lib/erl_interface/src/registry/reg_getf.c
new file mode 100644
index 0000000000..faed2f2df9
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_getf.c
@@ -0,0 +1,35 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include "reg.h"
+
+double ei_reg_getfval(ei_reg *reg, const char *key)
+{
+ ei_hash *tab;
+ ei_reg_obj *obj=NULL;
+
+ if (!key || !reg) return -1; /* return (double)EI_BADARG; */
+ tab = reg->tab;
+ if (!(obj=ei_hash_lookup(tab,key))) return -1; /* return EI_NOTFOUND; */
+ if (obj->attr & EI_DELET) return -1; /* return EI_NOTFOUND; */
+ if (ei_reg_typeof(obj) != EI_FLT) return -1; /* return (double)EI_TYPE; */
+
+ return obj->val.f;
+}
diff --git a/lib/erl_interface/src/registry/reg_geti.c b/lib/erl_interface/src/registry/reg_geti.c
new file mode 100644
index 0000000000..b746a4a92b
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_geti.c
@@ -0,0 +1,35 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include "reg.h"
+
+long ei_reg_getival(ei_reg *reg, const char *key)
+{
+ ei_hash *tab;
+ ei_reg_obj *obj=NULL;
+
+ if (!key || !reg) return -1; /* return EI_BADARG; */
+ tab = reg->tab;
+ if (!(obj=ei_hash_lookup(tab,key))) return -1; /* return EI_NOTFOUND; */
+ if (obj->attr & EI_DELET) return -1; /* return EI_NOTFOUND; */
+ if (ei_reg_typeof(obj) != EI_INT) return -1; /* return EI_TYPE; */
+
+ return obj->val.i;
+}
diff --git a/lib/erl_interface/src/registry/reg_getp.c b/lib/erl_interface/src/registry/reg_getp.c
new file mode 100644
index 0000000000..bacfdc05c4
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_getp.c
@@ -0,0 +1,39 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include "reg.h"
+
+const void *ei_reg_getpval(ei_reg *reg, const char *key, int *size)
+{
+ ei_hash *tab;
+ ei_reg_obj *obj;
+
+ if (!key || !reg) return NULL;
+ tab = reg->tab;
+
+ if ((!(obj=ei_hash_lookup(tab,key))) || /* return (const void *)EI_NOTFOUND; */
+ (obj->attr & EI_DELET) || /* return (const void *)EI_NOTFOUND; */
+ (ei_reg_typeof(obj) != EI_BIN)) /* return (const void *)EI_TYPE; */
+ return NULL;
+
+ if (size) *size=obj->size;
+ return obj->val.p;
+}
diff --git a/lib/erl_interface/src/registry/reg_gets.c b/lib/erl_interface/src/registry/reg_gets.c
new file mode 100644
index 0000000000..d6e6d67ebe
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_gets.c
@@ -0,0 +1,38 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include "reg.h"
+
+const char *ei_reg_getsval(ei_reg *reg, const char *key)
+{
+ ei_hash *tab;
+ ei_reg_obj *obj=NULL;
+
+ if (!key || !reg) return NULL; /* return (const char *)EI_BADARG; */
+ tab = reg->tab;
+
+ if ((!(obj=ei_hash_lookup(tab,key))) || /* return (const char *)EI_NOTFOUND; */
+ (obj->attr & EI_DELET) || /* return (const char *)EI_NOTFOUND; */
+ (ei_reg_typeof(obj) != EI_STR)) /* return (const char *)EI_TYPE; */
+ return NULL;
+
+ return obj->val.s;
+}
diff --git a/lib/erl_interface/src/registry/reg_make.c b/lib/erl_interface/src/registry/reg_make.c
new file mode 100644
index 0000000000..179cb8bf47
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_make.c
@@ -0,0 +1,49 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include "reg.h"
+
+
+/* make a new ei_reg_obj object. If the freelist for this registry is
+ * not empty, an object will be returned from there. Otherwise one
+ * will be created with malloc().
+ */
+ei_reg_obj *ei_reg_make(ei_reg *reg, int attr)
+{
+ ei_reg_obj *new=NULL;
+
+ if (reg->freelist) {
+ new = reg->freelist;
+ reg->freelist = new->next;
+ /* fprintf(stderr,"%s:%d: found %p on freelist\n",__FILE__,__LINE__,new); */
+ }
+ else {
+ new = malloc(sizeof(*new));
+ /* fprintf(stderr,"%s:%d: allocated %p\n",__FILE__,__LINE__,new); */
+ }
+
+ if (new) {
+ new->attr=attr | EI_DIRTY;
+ new->size=0;
+ new->next = NULL;
+ }
+ return new;
+}
diff --git a/lib/erl_interface/src/registry/reg_open.c b/lib/erl_interface/src/registry/reg_open.c
new file mode 100644
index 0000000000..0c2031707d
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_open.c
@@ -0,0 +1,41 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include "reg.h"
+
+/* open a registry */
+ei_reg *ei_reg_open(int size)
+{
+ ei_reg *new;
+
+ if (size <= 0) return NULL;
+
+ if (!(new = malloc(sizeof(*new)))) return NULL;
+
+ new->freelist = NULL;
+
+ if (!(new->tab = ei_hash_newtab(size))) {
+ free(new);
+ return NULL;
+ }
+
+ return new;
+}
diff --git a/lib/erl_interface/src/registry/reg_purge.c b/lib/erl_interface/src/registry/reg_purge.c
new file mode 100644
index 0000000000..329fd32f23
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_purge.c
@@ -0,0 +1,76 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include "reg.h"
+
+static ei_bucket *do_purge(ei_reg *reg, int i)
+{
+ ei_hash *tab = reg->tab;
+ ei_bucket *head = tab->tab[i];
+ ei_bucket *this, *next;
+ ei_reg_obj *obj;
+
+ /* first position special case */
+ while ((this=head)) {
+ obj = (ei_reg_obj*)(this->value); /* cast to eliminate 'const' warning */
+ if (obj->attr & EI_DELET) {
+ head = this->next;
+ ei_reg_free(reg,obj); /* free obj to freelist */
+ ei_hash_bfree(tab,this); /* free bucket to freelist */
+ tab->nelem--;
+ }
+ else break;
+ }
+
+ /* check remaining positions */
+ this = head;
+ while (this && this->next) {
+ next = this->next;
+ obj = (ei_reg_obj*)(next->value); /* cast to eliminate 'const' warning */
+ if (obj->attr & EI_DELET) {
+ this->next = next->next;
+ ei_reg_free(reg,obj); /* free object to freelist */
+ ei_hash_bfree(tab,next); /* free bucket to freelist */
+ tab->nelem--;
+ }
+ else this = this->next;
+ }
+
+ return head;
+}
+
+int ei_reg_purge(ei_reg *reg)
+{
+ ei_hash *tab;
+ int i;
+
+ if (!reg) return -1;
+ tab = reg->tab;
+
+ for (i=0;i<tab->size;i++) {
+ if ((tab->tab[i])) {
+ tab->tab[i] = do_purge(reg,i);
+ if (!tab->tab[i]) tab->npos--;
+ }
+ }
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/registry/reg_resize.c b/lib/erl_interface/src/registry/reg_resize.c
new file mode 100644
index 0000000000..8e4794ccf7
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_resize.c
@@ -0,0 +1,36 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include "reg.h"
+
+/* resize a registry - return the new size or -1 on error */
+int ei_reg_resize(ei_reg *reg, int newsize)
+{
+ ei_hash *newtab=NULL;
+
+ if (!reg) return -1;
+ if (newsize <= 0) return -1;
+
+ if ((newtab=ei_hash_resize(reg->tab,newsize))) {
+ reg->tab = newtab;
+ }
+
+ return reg->tab->size;
+}
diff --git a/lib/erl_interface/src/registry/reg_restore.c b/lib/erl_interface/src/registry/reg_restore.c
new file mode 100644
index 0000000000..27918d2364
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_restore.c
@@ -0,0 +1,323 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "eidef.h"
+#include "eiext.h"
+#include "reg.h"
+#include "eisend.h"
+#include "eirecv.h"
+#include "ei_connect_int.h"
+
+static int mn_start_restore(int fd, const erlang_pid *self, erlang_pid *mnesia, const char *mntab, long *count, long *maxkey,long *maxobj)
+{
+ char buf[EISMALLBUF];
+ char *bufp=buf;
+ char tmpbuf[64];
+ int index = 0;
+ erlang_msg msg;
+ int arity;
+ int version;
+ int i;
+ int needlink;
+ int needmsg;
+ int msglen;
+
+ /* set up rpc arguments */
+ /* { PidFrom, { call, Mod, Fun, Args, user }} */
+ ei_encode_version(buf,&index);
+ ei_encode_tuple_header(buf,&index,2);
+ ei_encode_pid(buf,&index,self); /* PidFrom */
+ ei_encode_tuple_header(buf,&index,5);
+ ei_encode_atom(buf,&index,"call"); /* call */
+ ei_encode_atom(buf,&index,EI_MNESIA_MODULE); /* Mod */
+ ei_encode_atom(buf,&index,EI_MNESIA_RESTORE); /* Fun */
+ ei_encode_list_header(buf,&index,2); /* Args: [ table, self() ] */
+ ei_encode_atom(buf,&index,mntab);
+ ei_encode_pid(buf,&index,self);
+ ei_encode_empty_list(buf,&index);
+ ei_encode_atom(buf,&index,"user"); /* user */
+
+ /* make the rpc call */
+ if (ei_send_reg_encoded(fd,self,"rex",buf,index)) return -1;
+
+ /* get the reply: expect link and message (not sure which will come first though) */
+ needlink = needmsg = 1;
+ while (needlink || needmsg) {
+ /* get message */
+ index = EISMALLBUF;
+ while (!(i = ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0))) index = EISMALLBUF;
+
+ switch (i) {
+ case ERL_LINK:
+ /* got link */
+ if (!needlink) return -1;
+ needlink = 0;
+ break;
+
+ case ERL_SEND:
+ /* got message - is it the right one? */
+ if (!needmsg) return -1;
+ else {
+ /* expecting { rex, { size, Pid, Count, MaxKey, MaxObj }} */
+ index = 0;
+ if (ei_decode_version(buf,&index,&version)
+ || ei_decode_tuple_header(buf,&index,&arity)
+ || (arity != 2)
+ || ei_decode_atom(buf,&index,tmpbuf)
+ || strcmp(tmpbuf,"rex")
+ || ei_decode_tuple_header(buf,&index,&arity)
+ || (arity != 5)
+ || ei_decode_atom(buf,&index,tmpbuf)
+ || strcmp(tmpbuf,EI_MNESIA_SIZE)
+ || ei_decode_pid(buf,&index,mnesia)
+ || ei_decode_long(buf,&index,count)
+ || ei_decode_long(buf,&index,maxkey)
+ || ei_decode_long(buf,&index,maxobj))
+ return -1; /* bad response from other side */
+
+ /* got msg */
+ needmsg = 0;
+ }
+ break;
+
+ default:
+ return -1; /* wasn't link or pid */
+ }
+ }
+ return 0;
+}
+
+static int mn_unlink(int fd)
+{
+ erlang_msg msg;
+ char buf[EISMALLBUF];
+ char *bufp=buf;
+ int index;
+ int msglen;
+
+ /* wait for unlink or exit */
+ while (1) {
+ index = EISMALLBUF;
+ switch (ei_recv_internal(fd,&bufp,&index,&msg,&msglen,1,0)) {
+ case 0: continue;
+ case ERL_UNLINK: return 0;
+ default: return -1;
+ }
+ }
+ return 0;
+}
+
+/* decode an object and insert it into the table */
+static int mn_decode_insert(ei_reg *reg, const char *msgbuf, int *index, char *key)
+{
+ long keylen;
+ long objlen;
+ long objtype;
+ void *objbuf = NULL;
+ long i;
+ double f;
+
+ if (ei_decode_long(msgbuf,index,&keylen)
+ || ei_decode_long(msgbuf,index,&objlen)
+ || ei_decode_long(msgbuf,index,&objtype))
+ return -1;
+
+
+ /* decode key */
+ if (ei_decode_string(msgbuf,index,key)) {
+ if (objbuf) free(objbuf);
+ return -1;
+ }
+
+ /* finally! decode object and insert in table */
+ /* don't forget to fix attributes (dirty bit for example) */
+
+ /* FIXME: added cast but 64 bit trouble I think */
+ switch ((int)objtype & EI_REG_TYPEMASK) {
+ case EI_INT:
+ if (ei_decode_long(msgbuf,index,&i)) return -1;
+ ei_reg_setival(reg,key,i);
+ break;
+
+ case EI_FLT:
+ if (ei_decode_double(msgbuf,index,&f)) return -1;
+ ei_reg_setfval(reg,key,f);
+ break;
+
+ case EI_STR:
+ objbuf = NULL;
+ if (objlen > 0) {
+ if (!(objbuf = malloc(objlen))) return -1;
+ if (ei_decode_string(msgbuf,index,objbuf)) {
+ free(objbuf);
+ return -1;
+ }
+ ei_reg_setsval(reg,key,objbuf);
+ }
+ else {
+ /* just a pointer to nothing */
+ if (ei_decode_long(msgbuf,index,&i)) return -1;
+ ei_reg_setsval(reg,key,NULL);
+ }
+ break;
+
+ case EI_BIN:
+ objbuf = NULL;
+ if (objlen > 0) {
+ if (!(objbuf = malloc(objlen))) return -1;
+ if (ei_decode_binary(msgbuf,index,objbuf,&i)) {
+ free(objbuf);
+ return -1;
+ }
+ /* assert(i == objlen) */
+ ei_reg_setpval(reg,key,objbuf,objlen);
+ }
+ else {
+ /* just a pointer to nothing */
+ if (ei_decode_long(msgbuf,index,&i)) return -1;
+ ei_reg_setpval(reg,key,(void *)i,0);
+ }
+ break;
+
+ default:
+ /* unknown type */
+ if (objbuf) free(objbuf);
+ return -1;
+ } /* switch */
+
+ return 0;
+}
+
+/* help function passed to hash_foreach, to clear dirty bits */
+/* use after successful restore */
+static int clean_obj(const char *key, const void *p)
+{
+ ei_reg_obj *obj = (ei_reg_obj *)p;
+
+ if (obj) obj->attr &= ~EI_DIRTY;
+
+ return 0;
+}
+
+int ei_reg_restore(int fd, ei_reg *reg, const char *mntab)
+{
+ int i,j;
+ char tag[32];
+ char sbuf[EISMALLBUF];
+ char *dbuf = NULL;
+ char *msgbuf = NULL;
+ char *keybuf = NULL;
+ erlang_pid self;
+ erlang_pid mnesia = {"",0,0,0};
+ erlang_msg msg;
+ int index = 0;
+ int len = 0;
+ int msglen;
+ int version = 0;
+ int arity = 0;
+ long count = 0;
+ long maxkey = 0;
+ long maxobj = 0;
+ ei_cnode *ec;
+
+ if (!reg || !mntab) return -1; /* return EI_BADARG; */
+
+ /* make a self pid */
+
+ if ((ec = ei_fd_to_cnode(fd)) == NULL) {
+ return -1;
+ }
+ strcpy(self.node,ei_thisnodename(ec));
+ self.num = fd;
+ self.serial = 0;
+ self.creation = ei_thiscreation(ec);
+
+
+ if (mn_start_restore(fd,&self,&mnesia,mntab,&count,&maxkey,&maxobj)) {
+ /* send exit *only* if we have pid */
+ if (mnesia.node[0]) ei_send_exit(fd,&self,&mnesia,"bad response from rpc start");
+ return -1;
+ }
+
+ if (count <= 0) {
+ ei_send_exit(fd,&self,&mnesia,"nothing to do");
+ return 0;
+ }
+
+ /* make sure receive buffer can handle largest expected message */
+ len = maxkey + maxobj + 512;
+ if (len > EISMALLBUF)
+ if (!(dbuf = malloc(index))) {
+ ei_send_exit(fd,&self,&mnesia,"cannot allocate space for incoming data");
+ return -1;
+ }
+ msgbuf = (dbuf ? dbuf : sbuf);
+
+ /* allocate space for largest key */
+ if (!(keybuf = malloc(maxkey+1))) goto restore_failure;
+
+ /* get this ball rolling */
+ index = 0;
+ ei_encode_version(msgbuf,&index);
+ ei_encode_tuple_header(msgbuf,&index,2);
+ ei_encode_atom(msgbuf,&index,"send_records");
+ ei_encode_pid(msgbuf,&index,&self);
+ if (ei_send_encoded(fd,&mnesia,msgbuf,index)) goto restore_failure;
+
+ /* read as much as possible, until count or EXIT */
+ for (i=0; i<count; i++) {
+ index = len;
+ while ((j = ei_recv_internal(fd,&msgbuf,&index,&msg,&msglen,1,0)) == 0) index = len;
+ if (j<0) goto restore_failure;
+
+ /* decode the first part of the message */
+ index = 0;
+ if ((msg.msgtype != ERL_SEND)
+ || ei_decode_version(msgbuf,&index,&version)
+ || ei_decode_tuple_header(msgbuf,&index,&arity)
+ || (arity != 6)
+ || ei_decode_atom(msgbuf,&index,tag)
+ || strcmp(tag,EI_MNESIA_RECV))
+ goto restore_failure;
+
+ /* decode the rest of the message and insert data into table */
+ if (mn_decode_insert(reg,msgbuf,&index,keybuf)) goto restore_failure;
+ }
+
+ /* wait for unlink */
+ if (mn_unlink(fd)) return -1;
+
+ /* clear all the dirty bits */
+ ei_hash_foreach(reg->tab,clean_obj);
+
+ /* success */
+ if (keybuf) free(keybuf);
+ if (dbuf) free(dbuf);
+ return 0;
+
+restore_failure:
+ ei_send_exit(fd,&self,&mnesia,"restore failure");
+ if (keybuf) free(keybuf);
+ if (dbuf) free(dbuf);
+ return -1;
+}
+
diff --git a/lib/erl_interface/src/registry/reg_set.c b/lib/erl_interface/src/registry/reg_set.c
new file mode 100644
index 0000000000..70ade09ffa
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_set.c
@@ -0,0 +1,78 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#ifdef VXWORKS
+#include <vxWorks.h>
+#endif
+
+#include <stdarg.h>
+#include "reg.h"
+
+int ei_reg_setval(ei_reg *reg, const char *key, int flags, ...)
+{
+ va_list ap;
+ int rval = 0;
+
+ if (!key || !reg) return -1; /* return EI_BADARG; */
+
+ va_start(ap,flags);
+
+ switch (flags & EI_REG_TYPEMASK) {
+ case EI_INT: {
+ long i;
+
+ i = va_arg(ap,long);
+ rval = ei_reg_setival(reg,key,i);
+ break;
+ }
+ case EI_FLT: {
+ double f;
+
+ f = va_arg(ap,double);
+ rval = ei_reg_setfval(reg,key,f);
+ break;
+ }
+ case EI_STR: {
+ char *s;
+
+ s = va_arg(ap,char*);
+ rval = ei_reg_setsval(reg,key,s);
+ break;
+ }
+ case EI_BIN: {
+ void *p;
+ int len;
+
+ p = va_arg(ap,void*);
+ len = va_arg(ap,int);
+ rval = ei_reg_setpval(reg,key,p,len);
+ break;
+ }
+
+ default:
+ rval = -1;
+ /* rval = EI_BADARG; */
+ }
+
+ /* clean up & return */
+ va_end(ap);
+ return rval;
+}
+
diff --git a/lib/erl_interface/src/registry/reg_setf.c b/lib/erl_interface/src/registry/reg_setf.c
new file mode 100644
index 0000000000..1021174074
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_setf.c
@@ -0,0 +1,61 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include "reg.h"
+
+int ei_reg_setfval(ei_reg *reg, const char *key, double f)
+{
+ ei_hash *tab;
+ ei_reg_obj *obj=NULL;
+
+ if (!key || !reg) return -1; /* return EI_BADARG; */
+ tab = reg->tab;
+
+ if ((obj=ei_hash_lookup(tab,key))) {
+ /* object with same name already exists */
+ switch (ei_reg_typeof(obj)) {
+ case EI_INT:
+ break;
+ case EI_FLT:
+ break;
+ case EI_STR:
+ if (obj->size > 0) free(obj->val.s);
+ break;
+ case EI_BIN:
+ if (obj->size > 0) free(obj->val.p);
+ break;
+ default:
+ return -1;
+ /* return EI_UNKNOWN; */
+ }
+ }
+ else {
+ /* object is new */
+ if (!(obj=ei_reg_make(reg,EI_FLT))) return -1; /* return EI_NOMEM; */
+ ei_hash_insert(tab,key,obj);
+ }
+
+ obj->attr = EI_FLT | EI_DIRTY;
+ obj->val.f=f;
+ obj->size = 0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/registry/reg_seti.c b/lib/erl_interface/src/registry/reg_seti.c
new file mode 100644
index 0000000000..430a3b6d47
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_seti.c
@@ -0,0 +1,62 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include "reg.h"
+
+/* set and get values */
+int ei_reg_setival(ei_reg *reg, const char *key, long i)
+{
+ ei_hash *tab;
+ ei_reg_obj *obj=NULL;
+
+ if (!key || !reg) return -1; /* return EI_BADARG; */
+ tab = reg->tab;
+
+ if ((obj=ei_hash_lookup(tab,key))) {
+ /* object with same name already exists */
+ switch (ei_reg_typeof(obj)) {
+ case EI_INT:
+ break;
+ case EI_FLT:
+ break;
+ case EI_STR:
+ if (obj->size > 0) free(obj->val.s);
+ break;
+ case EI_BIN:
+ if (obj->size > 0) free(obj->val.p);
+ break;
+ default:
+ return -1;
+ /* return EI_UNKNOWN; */
+ }
+ }
+ else {
+ /* object is new */
+ if (!(obj=ei_reg_make(reg,EI_INT))) return -1; /* return EI_NOMEM; */
+ ei_hash_insert(tab,key,obj);
+ }
+
+ obj->attr = EI_INT | EI_DIRTY;
+ obj->val.i=i;
+ obj->size = 0;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/registry/reg_setp.c b/lib/erl_interface/src/registry/reg_setp.c
new file mode 100644
index 0000000000..a994c14c78
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_setp.c
@@ -0,0 +1,62 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include "reg.h"
+
+int ei_reg_setpval(ei_reg *reg, const char *key, const void *p, int size)
+{
+ ei_hash *tab;
+ ei_reg_obj *obj=NULL;
+
+ if (size < 0) return -1;
+ if (!key || !reg) return -1; /* return EI_BADARG; */
+ tab = reg->tab;
+
+ if ((obj=ei_hash_lookup(tab,key))) {
+ /* object with same name already exists */
+ switch (ei_reg_typeof(obj)) {
+ case EI_INT:
+ break;
+ case EI_FLT:
+ break;
+ case EI_STR:
+ if (obj->size > 0) free(obj->val.s);
+ break;
+ case EI_BIN:
+ if (obj->size > 0) free(obj->val.p);
+ break;
+ default:
+ return -1;
+ /* return EI_UNKNOWN; */
+ }
+ }
+ else {
+ /* object is new */
+ if (!(obj=ei_reg_make(reg,EI_BIN))) return -1; /* return EI_NOMEM; */
+ ei_hash_insert(tab,key,obj);
+ }
+
+ obj->attr = EI_BIN | EI_DIRTY;
+ obj->val.p=(void *)p;
+ obj->size=size;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/registry/reg_sets.c b/lib/erl_interface/src/registry/reg_sets.c
new file mode 100644
index 0000000000..14bdb2699d
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_sets.c
@@ -0,0 +1,65 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "reg.h"
+
+int ei_reg_setsval(ei_reg *reg, const char *key, const char *s)
+{
+ ei_hash *tab;
+ ei_reg_obj *obj=NULL;
+ int len = 0;
+
+
+ if (!key || !reg) return -1; /* return EI_BADARG; */
+ tab = reg->tab;
+ if (s) len = strlen(s) +1;
+
+ if ((obj=ei_hash_lookup(tab,key))) {
+ /* object with same name already exists */
+ switch (ei_reg_typeof(obj)) {
+ case EI_INT:
+ break;
+ case EI_FLT:
+ break;
+ case EI_STR:
+ if (obj->size > 0) free(obj->val.s);
+ break;
+ case EI_BIN:
+ if (obj->size > 0) free(obj->val.p);
+ break;
+ default:
+ return -1;
+ /* return EI_UNKNOWN; */
+ }
+ }
+ else {
+ /* object is new */
+ if (!(obj=ei_reg_make(reg,EI_STR))) return -1; /* return EI_NOMEM; */
+ ei_hash_insert(tab,key,obj);
+ }
+
+ obj->attr = EI_STR | EI_DIRTY;
+ obj->val.s=(char *)s;
+ obj->size = len;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/registry/reg_stat.c b/lib/erl_interface/src/registry/reg_stat.c
new file mode 100644
index 0000000000..c3f669fd4f
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_stat.c
@@ -0,0 +1,41 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include "reg.h"
+
+/* Get object attributes.
+ * This function returns a COPY of the ei_reg_obj
+ * struct for an object.
+ */
+int ei_reg_stat(ei_reg *reg, const char *key, struct ei_reg_stat *obuf)
+{
+ ei_hash *tab;
+ ei_reg_obj *obj;
+
+ if (!key || !obuf || !reg) return -1; /* return EI_BADARG; */
+ tab = reg->tab;
+
+ if (!(obj=ei_hash_lookup(tab,key))) return -1; /* return EI_NOTFOUND; */
+
+ obuf->attr = obj->attr;
+ obuf->size = obj->size;
+
+ return 0;
+}
diff --git a/lib/erl_interface/src/registry/reg_tabstat.c b/lib/erl_interface/src/registry/reg_tabstat.c
new file mode 100644
index 0000000000..edfb19fa00
--- /dev/null
+++ b/lib/erl_interface/src/registry/reg_tabstat.c
@@ -0,0 +1,37 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ *
+
+ */
+#include "reg.h"
+
+/* get table information */
+int ei_reg_tabstat(ei_reg *reg, struct ei_reg_tabstat *obuf)
+{
+ ei_hash *tab;
+
+ if (!reg || !obuf) return -1; /* return EI_BADARG; */
+ tab = reg->tab;
+
+ obuf->npos = tab-> npos;
+ obuf->size = tab->size;
+ obuf->nelem = tab->nelem;
+ obuf->collisions = tab->nelem - tab->npos;
+
+ return 0;
+}
diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk
new file mode 100644
index 0000000000..c5f4c06037
--- /dev/null
+++ b/lib/erl_interface/vsn.mk
@@ -0,0 +1 @@
+EI_VSN = 3.6.4