Sophie

Sophie

distrib > Fedora > 17 > i386 > media > updates > by-pkgid > 675c8c8167236dfcf8d66da674f931e8 > files > 147

erlang-doc-R15B-03.3.fc17.noarch.rpm

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html xmlns:fn="http://www.w3.org/2005/02/xpath-functions">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="../otp_doc.css" type="text/css">
<title>Erlang -- Erl_Interface</title>
</head>
<body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" alink="#ff0000"><div id="container">
<script id="js" type="text/javascript" language="JavaScript" src="../js/flipmenu/flipmenu.js"></script><script id="js2" type="text/javascript" src="../js/erlresolvelinks.js"></script><script language="JavaScript" type="text/javascript">
            <!--
              function getWinHeight() {
                var myHeight = 0;
                if( typeof( window.innerHeight ) == 'number' ) {
                  //Non-IE
                  myHeight = window.innerHeight;
                } else if( document.documentElement && ( document.documentElement.clientWidth ||
                                                         document.documentElement.clientHeight ) ) {
                  //IE 6+ in 'standards compliant mode'
                  myHeight = document.documentElement.clientHeight;
                } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
                  //IE 4 compatible
                  myHeight = document.body.clientHeight;
                }
                return myHeight;
              }

              function setscrollpos() {
                var objf=document.getElementById('loadscrollpos');
                 document.getElementById("leftnav").scrollTop = objf.offsetTop - getWinHeight()/2;
              }

              function addEvent(obj, evType, fn){
                if (obj.addEventListener){
                obj.addEventListener(evType, fn, true);
                return true;
              } else if (obj.attachEvent){
                var r = obj.attachEvent("on"+evType, fn);
                return r;
              } else {
                return false;
              }
             }

             addEvent(window, 'load', setscrollpos);

             //--></script><div id="leftnav"><div class="innertube">
<img alt="Erlang logo" src="../erlang-logo.png"><br><small><a href="users_guide.html">User's Guide</a><br><a href="../pdf/otp-system-documentation-5.9.3.1.pdf">PDF</a><br><a href="../index.html">Top</a></small><p><strong>Interoperability Tutorial</strong><br><strong>User's Guide</strong><br><small>Version 5.9.3.1</small></p>
<br><a href="javascript:openAllFlips()">Expand All</a><br><a href="javascript:closeAllFlips()">Contract All</a><p><small><strong>Chapters</strong></small></p>
<ul class="flipMenu" imagepath="../js/flipmenu">
<li id="no" title="Introduction" expanded="false">Introduction<ul>
<li><a href="introduction.html">
              Top of chapter
            </a></li>
<li title="Purpose"><a href="introduction.html#id60800">Purpose</a></li>
<li title="Prerequisites"><a href="introduction.html#id60757">Prerequisites</a></li>
</ul>
</li>
<li id="no" title="Overview" expanded="false">Overview<ul>
<li><a href="overview.html">
              Top of chapter
            </a></li>
<li title="Built-In Mechanisms"><a href="overview.html#id62194">Built-In Mechanisms</a></li>
<li title="C and Java Libraries"><a href="overview.html#id60915">C and Java Libraries</a></li>
<li title="Standard Protocols"><a href="overview.html#id62774">Standard Protocols</a></li>
<li title="IC"><a href="overview.html#id61047">IC</a></li>
<li title="Old Applications"><a href="overview.html#id62555">Old Applications</a></li>
</ul>
</li>
<li id="no" title="Problem Example" expanded="false">Problem Example<ul>
<li><a href="example.html">
              Top of chapter
            </a></li>
<li title="Description"><a href="example.html#id63860">Description</a></li>
</ul>
</li>
<li id="no" title="Ports" expanded="false">Ports<ul>
<li><a href="c_port.html">
              Top of chapter
            </a></li>
<li title="Erlang Program"><a href="c_port.html#id58262">Erlang Program</a></li>
<li title="C Program"><a href="c_port.html#id62416">C Program</a></li>
<li title="Running the Example"><a href="c_port.html#id63496">Running the Example</a></li>
</ul>
</li>
<li id="loadscrollpos" title="Erl_Interface" expanded="true">Erl_Interface<ul>
<li><a href="erl_interface.html">
              Top of chapter
            </a></li>
<li title="Erlang Program"><a href="erl_interface.html#id63174">Erlang Program</a></li>
<li title="C Program"><a href="erl_interface.html#id63282">C Program</a></li>
<li title="Running the Example"><a href="erl_interface.html#id61784">Running the Example</a></li>
</ul>
</li>
<li id="no" title="Port drivers" expanded="false">Port drivers<ul>
<li><a href="c_portdriver.html">
              Top of chapter
            </a></li>
<li title="Port Drivers"><a href="c_portdriver.html#id61981">Port Drivers</a></li>
<li title="Erlang Program"><a href="c_portdriver.html#id62001">Erlang Program</a></li>
<li title="C Driver"><a href="c_portdriver.html#id62119">C Driver</a></li>
<li title="Running the Example"><a href="c_portdriver.html#id63970">Running the Example</a></li>
</ul>
</li>
<li id="no" title="C Nodes" expanded="false">C Nodes<ul>
<li><a href="cnode.html">
              Top of chapter
            </a></li>
<li title="Erlang Program"><a href="cnode.html#id64088">Erlang Program</a></li>
<li title="C Program"><a href="cnode.html#id64168">C Program</a></li>
<li title="Running the Example"><a href="cnode.html#id64499">Running the Example</a></li>
</ul>
</li>
<li id="no" title="NIFs" expanded="false">NIFs<ul>
<li><a href="nif.html">
              Top of chapter
            </a></li>
<li title="NIFs"><a href="nif.html#id64799">NIFs</a></li>
<li title="Erlang Program"><a href="nif.html#id64820">Erlang Program</a></li>
<li title="NIF library code"><a href="nif.html#id64884">NIF library code</a></li>
<li title="Running the Example"><a href="nif.html#id64985">Running the Example</a></li>
</ul>
</li>
</ul>
</div></div>
<div id="content">
<div class="innertube">
<h1>5 Erl_Interface</h1>
  
  <p>This is an example of how to solve the <span class="bold_code"><a href="example.html">example problem</a></span> by using a port and <span class="code">erl_interface</span>. It is necessary to read the <span class="bold_code"><a href="c_port.html">port example</a></span> before reading this chapter.</p>

  <h3><a name="id63174">5.1 
        Erlang Program</a></h3>
    
    <p>The example below shows an Erlang program communicating with a C program over a plain port with home made encoding.</p>
<div class="example"><pre>

-module(complex1).
-export([start/1, stop/0, init/1]).
-export([foo/1, bar/1]).

start(ExtPrg) -&gt;
    spawn(?MODULE, init, [ExtPrg]).
stop() -&gt;
    complex ! stop.

foo(X) -&gt;
    call_port({foo, X}).
bar(Y) -&gt;
    call_port({bar, Y}).

call_port(Msg) -&gt;
    complex ! {call, self(), Msg},
    receive
	{complex, Result} -&gt;
	    Result
    end.

init(ExtPrg) -&gt;
    register(complex, self()),
    process_flag(trap_exit, true),
    Port = open_port({spawn, ExtPrg}, [{packet, 2}]),
    loop(Port).

loop(Port) -&gt;
    receive
	{call, Caller, Msg} -&gt;
	    Port ! {self(), {command, encode(Msg)}},
	    receive
		{Port, {data, Data}} -&gt;
		    Caller ! {complex, decode(Data)}
	    end,
	    loop(Port);
	stop -&gt;
	    Port ! {self(), close},
	    receive
		{Port, closed} -&gt;
		    exit(normal)
	    end;
	{'EXIT', Port, Reason} -&gt;
	    exit(port_terminated)
    end.

encode({foo, X}) -&gt; [1, X];
encode({bar, Y}) -&gt; [2, Y].

decode([Int]) -&gt; Int.
</pre></div>    <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 <span class="code">term_to_binary/1</span> and <span class="code">binary_to_term/1</span> should be used. That is:</p>
    <div class="example"><pre>
open_port({spawn, ExtPrg}, [{packet, 2}])</pre></div>
    <p>is replaced with:</p>
    <div class="example"><pre>
open_port({spawn, ExtPrg}, [{packet, 2}, binary])</pre></div>
    <p>And:</p>
    <div class="example"><pre>
Port ! {self(), {command, encode(Msg)}},
receive
  {Port, {data, Data}} -&gt;
    Caller ! {complex, decode(Data)}
end</pre></div>
    <p>is replaced with:</p>
    <div class="example"><pre>
Port ! {self(), {command, term_to_binary(Msg)}},
receive
  {Port, {data, Data}} -&gt;
    Caller ! {complex, binary_to_term(Data)}
end</pre></div>
    <p>The resulting Erlang program is shown below.</p>
<div class="example"><pre>

-module(complex2).
-export([start/1, stop/0, init/1]).
-export([foo/1, bar/1]).

start(ExtPrg) -&gt;
    spawn(?MODULE, init, [ExtPrg]).
stop() -&gt;
    complex ! stop.

foo(X) -&gt;
    call_port({foo, X}).
bar(Y) -&gt;
    call_port({bar, Y}).

call_port(Msg) -&gt;
    complex ! {call, self(), Msg},
    receive
	{complex, Result} -&gt;
	    Result
    end.

init(ExtPrg) -&gt;
    register(complex, self()),
    process_flag(trap_exit, true),
    Port = open_port({spawn, ExtPrg}, [{packet, 2}, binary]),
    loop(Port).

loop(Port) -&gt;
    receive
	{call, Caller, Msg} -&gt;
	    Port ! {self(), {command, term_to_binary(Msg)}},
	    receive
		{Port, {data, Data}} -&gt;
		    Caller ! {complex, binary_to_term(Data)}
	    end,
	    loop(Port);
	stop -&gt;
	    Port ! {self(), close},
	    receive
		{Port, closed} -&gt;
		    exit(normal)
	    end;
	{'EXIT', Port, Reason} -&gt;
	    exit(port_terminated)
    end.
</pre></div>    <p>Note that calling <span class="code">complex2:foo/1</span> and <span class="code">complex2:bar/1</span> will result in the tuple <span class="code">{foo,X}</span> or <span class="code">{bar,Y}</span> being sent to the <span class="code">complex</span> 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>
  

  <h3><a name="id63282">5.2 
        C Program</a></h3>
    
    <p>The example below shows a C program communicating with an Erlang program over a plain port with home made encoding.</p>
<div class="example"><pre>

/* port.c */

typedef unsigned char byte;

int main() {
  int fn, arg, res;
  byte buf[100];

  while (read_cmd(buf) &gt; 0) {
    fn = buf[0];
    arg = buf[1];
    
    if (fn == 1) {
      res = foo(arg);
    } else if (fn == 2) {
      res = bar(arg);
    }

    buf[0] = res;
    write_cmd(buf, 1);
  }
}
      
</pre></div>    <p>Compared to the C program above
      used for the plain port the <span class="code">while</span>-loop must be rewritten. Messages coming from the port will be on the Erlang external term format. They should be converted into an <span class="code">ETERM</span> struct, a C struct similar to an Erlang term. The result of calling <span class="code">foo()</span> or <span class="code">bar()</span> must be converted to the Erlang external term format before being sent back to the port. But before calling any other <span class="code">erl_interface</span> function, the memory handling must be initiated.</p>
    <div class="example"><pre>
erl_init(NULL, 0);</pre></div>
    <p>For reading from and writing to the port the functions <span class="code">read_cmd()</span> and <span class="code">write_cmd()</span> from the erl_comm.c example below 
      can still be used.
    </p>
<div class="example"><pre>

/* erl_comm.c */

typedef unsigned char byte;

read_cmd(byte *buf)
{
  int len;

  if (read_exact(buf, 2) != 2)
    return(-1);
  len = (buf[0] &lt;&lt; 8) | buf[1];
  return read_exact(buf, len);
}

write_cmd(byte *buf, int len)
{
  byte li;

  li = (len &gt;&gt; 8) &amp; 0xff;
  write_exact(&amp;li, 1);
  
  li = len &amp; 0xff;
  write_exact(&amp;li, 1);

  return write_exact(buf, len);
}

read_exact(byte *buf, int len)
{
  int i, got=0;

  do {
    if ((i = read(0, buf+got, len-got)) &lt;= 0)
      return(i);
    got += i;
  } while (got&lt;len);

  return(len);
}

write_exact(byte *buf, int len)
{
  int i, wrote = 0;

  do {
    if ((i = write(1, buf+wrote, len-wrote)) &lt;= 0)
      return (i);
    wrote += i;
  } while (wrote&lt;len);

  return (len);
}
</pre></div>    <p>The function <span class="code">erl_decode()</span> from <span class="code">erl_marshal</span> will convert the binary into an <span class="code">ETERM</span> struct.</p>
    <div class="example"><pre>
int main() {
  ETERM *tuplep;

  while (read_cmd(buf) &gt; 0) {
    tuplep = erl_decode(buf);</pre></div>
    <p>In this case <span class="code">tuplep</span> now points to an <span class="code">ETERM</span> struct representing a tuple with two elements; the function name (atom) and the argument (integer). By using the function <span class="code">erl_element()</span> from <span class="code">erl_eterm</span> it is possible to extract these elements, which also must be declared as pointers to an <span class="code">ETERM</span> struct.</p>
    <div class="example"><pre>
    fnp = erl_element(1, tuplep);
    argp = erl_element(2, tuplep);</pre></div>
    <p>The macros <span class="code">ERL_ATOM_PTR</span> and <span class="code">ERL_INT_VALUE</span> from <span class="code">erl_eterm</span> 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>
    <div class="example"><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></div>
    <p>Now an <span class="code">ETERM</span> struct representing the integer result can be constructed using the function <span class="code">erl_mk_int()</span> from <span class="code">erl_eterm</span>. It is also possible to use the function <span class="code">erl_format()</span> from the module <span class="code">erl_format</span>.</p>
    <div class="example"><pre>
    intp = erl_mk_int(res);</pre></div>
    <p>The resulting <span class="code">ETERM</span> struct is converted into the Erlang external term format using the function <span class="code">erl_encode()</span> from <span class="code">erl_marshal</span> and sent to Erlang using <span class="code">write_cmd()</span>.</p>
    <div class="example"><pre>
    erl_encode(intp, buf);
    write_cmd(buf, erl_eterm_len(intp));</pre></div>
    <p>Last, the memory allocated by the <span class="code">ETERM</span> creating functions must be freed.</p>
    <div class="example"><pre>
    erl_free_compound(tuplep);
    erl_free_term(fnp);
    erl_free_term(argp);
    erl_free_term(intp);</pre></div>
    <p>The resulting C program is shown below:</p>
<div class="example"><pre>

/* ei.c */

#include "erl_interface.h"
#include "ei.h"

typedef unsigned char byte;

int main() {
  ETERM *tuplep, *intp;
  ETERM *fnp, *argp;
  int res;
  byte buf[100];
  long allocated, freed;

  erl_init(NULL, 0);

  while (read_cmd(buf) &gt; 0) {
    tuplep = erl_decode(buf);
    fnp = erl_element(1, tuplep);
    argp = erl_element(2, tuplep);
    
    if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) {
      res = foo(ERL_INT_VALUE(argp));
    } else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 17) == 0) {
      res = bar(ERL_INT_VALUE(argp));
    }

    intp = erl_mk_int(res);
    erl_encode(intp, buf);
    write_cmd(buf, erl_term_len(intp));

    erl_free_compound(tuplep);
    erl_free_term(fnp);
    erl_free_term(argp);
    erl_free_term(intp);
  }
}
      
</pre></div>  

  <h3><a name="id61784">5.3 
        Running the Example</a></h3>
    
    <p>1. Compile the C code, providing the paths to the include files <span class="code">erl_interface.h</span> and <span class="code">ei.h</span>, and to the libraries <span class="code">erl_interface</span> and <span class="code">ei</span>.</p>
    <div class="example"><pre>
unix&gt; <span class="bold_code">gcc -o extprg -I/usr/local/otp/lib/erl_interface-3.2.1/include \\ </span>
<span class="bold_code">      -L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ </span>
<span class="bold_code">      complex.c erl_comm.c ei.c -lerl_interface -lei</span></pre></div>
    <p>In R5B and later versions of OTP, the <span class="code">include</span> and <span class="code">lib</span> directories are situated under <span class="code">OTPROOT/lib/erl_interface-VSN</span>, where <span class="code">OTPROOT</span> is the root directory of the OTP installation (<span class="code">/usr/local/otp</span> in the example above) and <span class="code">VSN</span> is the version of the <span class="code">erl_interface</span> application (3.2.1 in the example above).      <br>

      In R4B and earlier versions of OTP, <span class="code">include</span> and <span class="code">lib</span> are situated under <span class="code">OTPROOT/usr</span>.</p>
    <p>2. Start Erlang and compile the Erlang code.</p>
    <div class="example"><pre>
unix&gt; <span class="bold_code">erl</span>
Erlang (BEAM) emulator version 4.9.1.2

Eshell V4.9.1.2 (abort with ^G)
1&gt; <span class="bold_code">c(complex2).</span>
{ok,complex2}</pre></div>
    <p>3. Run the example.</p>
    <div class="example"><pre>
2&gt; <span class="bold_code">complex2:start("extprg").</span>
&lt;0.34.0&gt;
3&gt; <span class="bold_code">complex2:foo(3).</span>
4
4&gt; <span class="bold_code">complex2:bar(5).</span>
10
5&gt; <span class="bold_code">complex2:bar(352).</span>
704
6&gt; <span class="bold_code">complex2:stop().</span>
stop</pre></div>
  
</div>
<div class="footer">
<hr>
<p>Copyright © 2000-2012 Ericsson AB. All Rights Reserved.</p>
</div>
</div>
</div></body>
</html>