diff options
Diffstat (limited to 'system/doc/tutorial/erl_interface.xmlsrc')
-rw-r--r-- | system/doc/tutorial/erl_interface.xmlsrc | 142 |
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> +<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> + |