aboutsummaryrefslogtreecommitdiffstats
path: root/lib/erl_interface/src
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/src
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/erl_interface/src')
-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
166 files changed, 25352 insertions, 0 deletions
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;
+}