aboutsummaryrefslogtreecommitdiffstats
path: root/system/doc/tutorial/erl_interface.xmlsrc
diff options
context:
space:
mode:
Diffstat (limited to 'system/doc/tutorial/erl_interface.xmlsrc')
-rw-r--r--system/doc/tutorial/erl_interface.xmlsrc142
1 files changed, 142 insertions, 0 deletions
diff --git a/system/doc/tutorial/erl_interface.xmlsrc b/system/doc/tutorial/erl_interface.xmlsrc
new file mode 100644
index 0000000000..752eec1d3e
--- /dev/null
+++ b/system/doc/tutorial/erl_interface.xmlsrc
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2000</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Erl_Interface</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>erl_interface.xml</file>
+ </header>
+ <p>This is an example of how to solve the <seealso marker="example">example problem</seealso> by using a port and <c>erl_interface</c>. It is necessary to read the <seealso marker="c_port">port example</seealso> before reading this chapter.</p>
+
+ <section>
+ <title>Erlang Program</title>
+ <p>The example below shows an Erlang program communicating with a C program over a plain port with home made encoding.</p>
+ <codeinclude file="complex1.erl" type="erl"/>
+ <p>Compared to the Erlang module
+ above used for the plain port, there are two differences when using Erl_Interface on the C side: Since Erl_Interface operates on the Erlang external term format the port must be set to use binaries and, instead of inventing an encoding/decoding scheme, the BIFs <c>term_to_binary/1</c> and <c>binary_to_term/1</c> should be used. That is:</p>
+ <pre>
+open_port({spawn, ExtPrg}, [{packet, 2}])</pre>
+ <p>is replaced with:</p>
+ <pre>
+open_port({spawn, ExtPrg}, [{packet, 2}, binary])</pre>
+ <p>And:</p>
+ <pre>
+Port ! {self(), {command, encode(Msg)}},
+receive
+ {Port, {data, Data}} ->
+ Caller ! {complex, decode(Data)}
+end</pre>
+ <p>is replaced with:</p>
+ <pre>
+Port ! {self(), {command, term_to_binary(Msg)}},
+receive
+ {Port, {data, Data}} ->
+ Caller ! {complex, binary_to_term(Data)}
+end</pre>
+ <p>The resulting Erlang program is shown below.</p>
+ <codeinclude file="complex2.erl" type="erl"/>
+ <p>Note that calling <c>complex2:foo/1</c> and <c>complex2:bar/1</c> will result in the tuple <c>{foo,X}</c> or <c>{bar,Y}</c> being sent to the <c>complex</c> process, which will code them as binaries and send them to the port. This means that the C program must be able to handle these two tuples.</p>
+ </section>
+
+ <section>
+ <title>C Program</title>
+ <p>The example below shows a C program communicating with an Erlang program over a plain port with home made encoding.</p>
+ <codeinclude file="port.c" type="c"/>
+ <p>Compared to the C program above
+ used for the plain port the <c>while</c>-loop must be rewritten. Messages coming from the port will be on the Erlang external term format. They should be converted into an <c>ETERM</c> struct, a C struct similar to an Erlang term. The result of calling <c>foo()</c> or <c>bar()</c> must be converted to the Erlang external term format before being sent back to the port. But before calling any other <c>erl_interface</c> function, the memory handling must be initiated.</p>
+ <pre>
+erl_init(NULL, 0);</pre>
+ <p>For reading from and writing to the port the functions <c>read_cmd()</c> and <c>write_cmd()</c> from the erl_comm.c example below
+ can still be used.
+ </p>
+ <codeinclude file="erl_comm.c" type="c"/>
+ <p>The function <c>erl_decode()</c> from <c>erl_marshal</c> will convert the binary into an <c>ETERM</c> struct.</p>
+ <pre>
+int main() {
+ ETERM *tuplep;
+
+ while (read_cmd(buf) > 0) {
+ tuplep = erl_decode(buf);</pre>
+ <p>In this case <c>tuplep</c> now points to an <c>ETERM</c> struct representing a tuple with two elements; the function name (atom) and the argument (integer). By using the function <c>erl_element()</c> from <c>erl_eterm</c> it is possible to extract these elements, which also must be declared as pointers to an <c>ETERM</c> struct.</p>
+ <pre>
+ fnp = erl_element(1, tuplep);
+ argp = erl_element(2, tuplep);</pre>
+ <p>The macros <c>ERL_ATOM_PTR</c> and <c>ERL_INT_VALUE</c> from <c>erl_eterm</c> can be used to obtain the actual values of the atom and the integer. The atom value is represented as a string. By comparing this value with the strings "foo" and "bar" it can be decided which function to call.</p>
+ <pre>
+ if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) {
+ res = foo(ERL_INT_VALUE(argp));
+ } else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 3) == 0) {
+ res = bar(ERL_INT_VALUE(argp));
+ }</pre>
+ <p>Now an <c>ETERM</c> struct representing the integer result can be constructed using the function <c>erl_mk_int()</c> from <c>erl_eterm</c>. It is also possible to use the function <c>erl_format()</c> from the module <c>erl_format</c>.</p>
+ <pre>
+ intp = erl_mk_int(res);</pre>
+ <p>The resulting <c>ETERM</c> struct is converted into the Erlang external term format using the function <c>erl_encode()</c> from <c>erl_marshal</c> and sent to Erlang using <c>write_cmd()</c>.</p>
+ <pre>
+ erl_encode(intp, buf);
+ write_cmd(buf, erl_eterm_len(intp));</pre>
+ <p>Last, the memory allocated by the <c>ETERM</c> creating functions must be freed.</p>
+ <pre>
+ erl_free_compound(tuplep);
+ erl_free_term(fnp);
+ erl_free_term(argp);
+ erl_free_term(intp);</pre>
+ <p>The resulting C program is shown below:</p>
+ <codeinclude file="ei.c" type="c"/>
+ </section>
+
+ <section>
+ <title>Running the Example</title>
+ <p>1. Compile the C code, providing the paths to the include files <c>erl_interface.h</c> and <c>ei.h</c>, and to the libraries <c>erl_interface</c> and <c>ei</c>.</p>
+ <pre>
+unix> <input>gcc -o extprg -I/usr/local/otp/lib/erl_interface-3.2.1/include \\ </input>
+<input> -L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ </input>
+<input> complex.c erl_comm.c ei.c -lerl_interface -lei</input></pre>
+ <p>In R5B and later versions of OTP, the <c>include</c> and <c>lib</c> directories are situated under <c>OTPROOT/lib/erl_interface-VSN</c>, where <c>OTPROOT</c> is the root directory of the OTP installation (<c>/usr/local/otp</c> in the example above) and <c>VSN</c> is the version of the <c>erl_interface</c> application (3.2.1 in the example above). <br></br>
+
+ In R4B and earlier versions of OTP, <c>include</c> and <c>lib</c> are situated under <c>OTPROOT/usr</c>.</p>
+ <p>2. Start Erlang and compile the Erlang code.</p>
+ <pre>
+unix> <input>erl</input>
+Erlang (BEAM) emulator version 4.9.1.2
+
+Eshell V4.9.1.2 (abort with ^G)
+1> <input>c(complex2).</input>
+{ok,complex2}</pre>
+ <p>3. Run the example.</p>
+ <pre>
+2> <input>complex2:start("extprg").</input>
+&lt;0.34.0>
+3> <input>complex2:foo(3).</input>
+4
+4> <input>complex2:bar(5).</input>
+10
+5> <input>complex2:bar(352).</input>
+704
+6> <input>complex2:stop().</input>
+stop</pre>
+ </section>
+</chapter>
+