# ei

### C LIBRARY

ei

### C LIBRARY SUMMARY

routines for handling the erlang binary term format

### DESCRIPTION

The library `ei` contains macros and functions to encode and decode the erlang binary term format.

With `ei`, you can convert atoms, lists, numbers and binaries to and from the binary format. This is useful when writing port programs and drivers. `ei` uses a given buffer, and no dynamic memory (with the exception of `ei_decode_fun()`), and is often quite fast.

It also handles C-nodes, C-programs that talks erlang distribution with erlang nodes (or other C-nodes) using the erlang distribution format. The difference between `ei` and `erl_interface` is that `ei` uses the binary format directly when sending and receiving terms. It is also thread safe, and using threads, one process can handle multiple C-nodes. The `erl_interface` library is built on top of `ei`, but of legacy reasons, it doesn't allow for multiple C-nodes. In general, `ei` is the preferred way of doing C-nodes.

The decode and encode functions use a buffer an index into the buffer, which points at the point where to encode and decode. The index is updated to point right after the term encoded/decoded. No checking is done whether the term fits in the buffer or not. If encoding goes outside the buffer, the program may crash.

All functions takes two parameter, `buf` is a pointer to the buffer where the binary data is / will be, `index` is a pointer to an index into the buffer. This parameter will be incremented with the size of the term decoded / encoded. The data is thus at `buf[*index]` when an `ei` function is called.

The encode functions all assumes that the `buf` and `index` parameters points to a buffer big enough for the data. To get the size of an encoded term, without encoding it, pass `NULL` instead of a buffer pointer. The `index` parameter will be incremented, but nothing will be encoded. This is the way in `ei` to "preflight" term encoding.

There are also encode-functions that uses a dynamic buffer. It is often more convenient to use these to encode data. All encode funcions comes in two versions: those starting with `ei_x`, uses a dynamic buffer.

All functions return `0` if successful, and `-1` if not. (For instance, if a term is not of the expected type, or the data to decode is not a valid erlang term.)

Some of the decode-functions needs a preallocated buffer. This buffer must be allocated big enough, and for non compound types the `ei_get_type()` function returns the size required (note that for strings an extra byte is needed for the 0 string terminator).

### EXPORTS

`int ei_encode_version(char *buf, int *index)`
`int ei_x_encode_version(ei_x_buff* x)`

Encodes a version magic number for the binary format. Must be the first token in a binary term.

`int ei_encode_long(char *buf, int *index, long p)`
`int ei_x_encode_long(ei_x_buff* x, long p)`

Encodes a long integer in the binary format. Note that if the code is 64 bits the function ei_encode_long() is exactly the same as ei_encode_longlong().

`int ei_encode_ulong(char *buf, int *index, unsigned long p)`
`int ei_x_encode_ulong(ei_x_buff* x, unsigned long p)`

Encodes an unsigned long integer in the binary format. Note that if the code is 64 bits the function ei_encode_ulong() is exactly the same as ei_encode_ulonglong().

`int ei_encode_longlong(char *buf, int *index, long long p)`
`int ei_x_encode_longlong(ei_x_buff* x, long long p)`

Encodes a GCC long long or Visual C++ __int64 (64 bit) integer in the binary format.

`int ei_encode_ulonglong(char *buf, int *index, unsigned long long p)`
`int ei_x_encode_ulonglong(ei_x_buff* x, unsigned long long p)`

Encodes a GCC unsigned long long or Visual C++ unsigned __int64 (64 bit) integer in the binary format.

`int ei_encode_bignum(char *buf, int *index, mpz_t obj)`
`int ei_x_encode_bignum(ei_x_buff *x, mpz_t obj)`

Encodes a GMP `mpz_t` integer to binary format. To use this function the ei library needs to be configured and compiled to use the GMP library.

`int ei_encode_double(char *buf, int *index, double p)`
`int ei_x_encode_double(ei_x_buff* x, double p)`

Encodes a double-precision (64 bit) floating point number in the binary format.

`int ei_encode_boolean(char *buf, int *index, int p)`

Encodes a boolean value, as the atom `true` if p is not zero or `false` if p is zero.

`int ei_encode_char(char *buf, int *index, char p)`

Encodes a char (8-bit) as an integer in the binary format.

`int ei_encode_string(char *buf, int *index, const char *p)`
`int ei_encode_string_len(char *buf, int *index, const char *p, int len)`
`int ei_x_encode_string(ei_x_buff* x, const char *p)`
`int ei_x_encode_string_len(ei_x_buff* x, const char* s, int len)`

Encodes a string in the binary format. (A string in erlang is a list, but is encoded as a character array in the binary format.) The string should be zero-terminated, except for the `ei_x_encode_string_len()` function.

`int ei_encode_atom(char *buf, int *index, const char *p)`
`int ei_encode_atom_len(char *buf, int *index, const char *p, int len)`
`int ei_x_encode_atom(ei_x_buff* x, const char *p)`
`int ei_x_encode_atom_len(ei_x_buff* x, const char *p, int len)`

Encodes an atom in the binary format. The `p` parameter is the name of the atom. Only upto `MAXATOMLEN` bytes are encoded. The name should be zero-terminated, except for the `ei_x_encode_atom_len()` function.

`int ei_encode_binary(char *buf, int *index, const void *p, long len)`
`int ei_x_encode_binary(ei_x_buff* x, const void *p, long len)`

Encodes a binary in the binary format. The data is at `p`, of `len` bytes length.

`int ei_encode_pid(char *buf, int *index, const erlang_pid *p)`
`int ei_x_encode_pid(ei_x_buff* x, const erlang_pid *p)`

Encodes an erlang process identifier, pid, in the binary format. The `p` parameter points to an `erlang_pid` structure (which should have been obtained earlier with `ei_decode_pid()`).

`int ei_encode_fun(char *buf, int *index, const erlang_fun *p)`
`int ei_x_encode_fun(ei_x_buff* x, const erlang_fun* fun)`

Encodes a fun in the binary format. The `p` parameter points to an `erlang_fun` structure. The `erlang_fun` is not freed automatically, the `free_fun` should be called if the fun is not needed after encoding.

`int ei_encode_port(char *buf, int *index, const erlang_port *p)`

Encodes an erlang port in the binary format. The `p` parameter points to a `erlang_port` structure (which should have been obtained earlier with `ei_decode_port()`.

`int ei_encode_ref(char *buf, int *index, const erlang_ref *p)`

Encodes an erlang reference in the binary format. The `p` parameter points to a `erlang_ref` structure (which should have been obtained earlier with `ei_decode_ref()`.

`int ei_encode_term(char *buf, int *index, void *t)`
`int ei_x_encode_term(ei_x_buff* x, void *t)`

This function encodes an `ETERM`, as obtained from `erl_interface`. The `t` parameter is actually an `ETERM` pointer. This function doesn't free the `ETERM`.

`int ei_encode_trace(char *buf, int *index, const erlang_trace *p)`

This function encodes an erlang trace token in the binary format. The `p` parameter points to a `erlang_trace` structure (which should have been obtained earlier with `ei_decode_trace()`.

`int ei_encode_tuple_header(char *buf, int *index, int arity)`
`int ei_x_encode_tuple_header(ei_x_buff* x, int arity)`

This function encodes a tuple header, with a specified arity. The next `arity` terms encoded will be the elements of the tuple. Tuples and lists are encoded recursively, so that a tuple may contain another tuple or list.

E.g. to encode the tuple `{a, {b, {}}}`:

    ei_encode_tuple_header(buf, &i, 2);
    ei_encode_atom(buf, &i, "a");
    ei_encode_tuple_header(buf, &i, 2);
    ei_encode_atom(buf, &i, "b");
    ei_encode_tuple_header(buf, &i, 0);

`int ei_encode_list_header(char *buf, int *index, int arity)`
`int ei_x_encode_list_header(ei_x_buff* x, int arity)`

This function encodes a list header, with a specified arity. The next `arity+1` terms are the elements (actually it's `arity` cons cells) and the tail of the list. Lists and tuples are encoded recursively, so that a list may contain another list or tuple.

E.g. to encode the list `[c, d, [e | f]]`:

    ei_encode_list_header(buf, &i, 3);
    ei_encode_atom(buf, &i, "c");
    ei_encode_atom(buf, &i, "d");
    ei_encode_list_header(buf, &i, 1);
    ei_encode_atom(buf, &i, "e");
    ei_encode_atom(buf, &i, "f");
    ei_encode_empty_list(buf, &i);

| It may seem that there is no way to create a list without knowing the number of elements in advance. But indeed there is a way. Note that the list `[a, b, c]` can be written as `[a | [b | [c]]]`. Using this, a list can be written as conses.

To encode a list, without knowing the arity in advance:

    while (something()) {
        ei_x_encode_list_header(&x, 1);
        ei_x_encode_ulong(&x, i); /* just an example */
    }
    ei_x_encode_empty_list(&x);

`int ei_encode_empty_list(char* buf, int* index)`
`int ei_x_encode_empty_list(ei_x_buff* x)`

This function encodes an empty list. It's often used at the tail of a list.

`intei_get_type(const char *buf, const int *index, int *type, int *size)`

This function returns the type in `type` and size in `size` of the encoded term. The types are For strings and atoms, size is the number of characters not including the terminating 0. For binaries, `size` is the number of bytes. For lists and tuples, `size` is the arity of the object.

EI_TYPE_INTEGER
  This is an Erlang integer. The returned `size` is 0. FIXME why not give the size needed back???? Depending on the actual size of the integer you can use one of `ei_decode_char()`, `ei_decode_long()`, `ei_decode_ulong()`, `ei_decode_longlong()`, `ei_decode_ulonglong()` and if this library was compiled with GNU MP bignum support with `ei_decode_bignum()`.
EI_TYPE_FLOAT
  This is an Erlang float. The returned `size` is 0. FIXME "no size is returned" ????
EI_TYPE_ATOM
  This is an Erlang atom. The returned `size` is the number of bytes you need to store the atom name including the terminating \\0. You can get the atom name as a C string using `ei_decode_atom()`. If the atom name is one of `true` or `false` you can get the boolean value using `ei_decode_boolean()`. FIXME limitations, \0 in atom name ??
EI_TYPE_BINARY
EI_TYPE_FUN
  FIXME !!!!!
EI_TYPE_PID
EI_TYPE_PORT
  ei_decode_port()
EI_TYPE_REF
  ei_decode_ref()
EI_TYPE_LIST
  This is an Erlang list. The list can be decoded as a string using `ei_decode_string()` if the arguments to the list are all integers with values between 0 and 255.
EI_TYPE_TUPLE
EI_TYPE_TERM
  FIXME
EI_TYPE_TRACE
  FIXME

For other types, `size` is 0. In all cases, `index` is left unchanged.

`int ei_decode_version(const char *buf, int *index, int *version)`

This function decodes the version magic number for the erlang binary term format. It must be the first token in a binary term.

`int ei_decode_long(const char *buf, int *index, long *p)`

This function decodes a long integer from the binary format. Note that if the code is 64 bits the function ei_decode_long() is exactly the same as ei_decode_longlong().

`int ei_decode_ulong(const char *buf, int *index, unsigned long *p)`

This function decodes an unsigned long integer from the binary format. Note that if the code is 64 bits the function ei_decode_ulong() is exactly the same as ei_decode_ulonglong().

`int ei_decode_longlong(const char *buf, int *index, long long *p)`

This function decodes a GCC long long or Visual C++ __int64 (64 bit) integer from the binary format.

`int ei_decode_ulonglong(const char *buf, int *index, unsigned long long *p)`

This function decodes a GCC unsigned long long or Visual C++ unsigned __int64 (64 bit) integer from the binary format.

`int ei_decode_bignum(const char *buf, int *index, mpz_t obj)`

This function decodes an integer in the binary format to a GMP `mpz_t` integer. To use this function the ei library needs to be configured and compiled to use the GMP library.

`int ei_decode_double(const char *buf, int *index, double *p)`

This function decodes an double-precision (64 bit) floating point number from the binary format.

`int ei_decode_boolean(const char *buf, int *index, int *p)`

This function decodes a boolean value from the binary format. A boolean is actually an atom, `true` decodes 1 and `false` decodes 0.

`int ei_decode_char(const char *buf, int *index, char *p)`

This function decodes a char (8-bit) integer from the binary format.

`int ei_decode_string(const char *buf, int *index, char *p)`

This function decodes a string from the binary format. A string in erlang is a list of integers between 0 and 255. Note that since the string is just a list, sometimes lists are encoded as strings by `term_to_binary/1`, even if it was not intended.

The string is copied to `p`, and enough space must be allocated. The space required can be fetched with `ei_get_type()`. (Don't forget the ending 0.)

`int ei_decode_atom(const char *buf, int *index, char *p)`

This function decodes an atom from the binary format. The name of the atom is placed at `p`. There can be at most `MAXATOMLEN` bytes placed in the buffer.

`int ei_decode_binary(const char *buf, int *index, void *p, long *len)`

This function decodes a binary from the binary format. The `len` parameter is set to the actual size of the binary. Note that `ei_decode_binary()` assumes that there are enough room for the binary. The size required can be fetched by `ei_get_type()`.

`int ei_decode_fun(const char *buf, int *index, erlang_fun *p)`
`void free_fun(erlang_fun* f)`

This function decodes a fun from the binary format. The `p` parameter should be NULL or point to an `erlang_fun` structure. This is the only decode function that allocates memory; when the `erlang_fun` is no longer needed, it should be freed with `free_fun`. (This has to do with the arbitrary size of the environment for a fun.)

`int ei_decode_pid(const char *buf, int *index, erlang_pid *p)`

Decodes a pid, process identifier, from the binary format.

`int ei_decode_port(const char *buf, int *index, erlang_port *p)`

This function decodes a port identifier from the binary format.

`int ei_decode_ref(const char *buf, int *index, erlang_ref *p)`

This function decodes a reference from the binary format.

`int ei_decode_trace(const char *buf, int *index, erlang_trace *p)`

Decodes an erlang trace token from the binary format.

`int ei_decode_tuple_header(const char *buf, int *index, int *arity)`

This function decodes a tuple header, the number of elements is returned in `arity`. The tuple elements follows in order in the buffer.

`int ei_decode_list_header(const char *buf, int *index, int *arity)`

This function decodes a list header from the binary format. The number of elements is returned in `arity`. The `arity+1` elements follows (the last one is the tail of the list, normally an empty list.) If `arity` is `0`, it's an empty list.

Note that lists are encoded as strings, if they consist entirely of integers in the range 0..255. This function will not decode such strings, use `ei_decode_string()` instead.

`int ei_decode_ei_term(const char* buf, int* index, ei_term* term)`

This function decodes any term, or at least tries to. If the term pointed at by `*index` in `buf` fits in the `term` union, it is decoded, and the appropriate field in `term->value` is set, and `*index` is incremented by the term size.

The function returns 0 on successful encoding, -1 on error, and 1 if the term seems alright, but does not fit in the `term` structure. If it returns 0, the `index` will be incremented, and the `term` contains the decoded term.

The `term` structure will contain the arity for a tuple or list, size for a binary, string or atom. It will contains a term if it's any of the following: integer, float, atom, pid, port or ref.

`int ei_decode_term(const char *buf, int *index, void *t)`

This function decodes a term from the binary format. The term is return in `t` as a `ETERM*`, so `t` is actually an `ETERM**` (see `erl_interface(3)`. The term should later be deallocated. FIXME note that this function belongs to erl_interface library

`int ei_print_term(FILE* fp, const char* buf, int* index)`
`int ei_s_print_term(char** s, const char* buf, int* index)`

This function prints a term, in clear text, to the file given by `fp`, or the buffer pointed to by `s`. It tries to resemble the term printing in the erlang shell.

In `ei_s_print_term()`, the parameter `s` should point to a dynamically (malloc) allocated string of `BUFSIZ` bytes or a NULL pointer. The string may be reallocated (and `*s` may be updated) by this function if the result is more than `BUFSIZ` characters. The string returned is zero-terminated.

The return value is the number of characters written to the file or string, or -1 if `buf[index]` doesn't contain a valid term. Unfortunately, I/O errors on `fp` is not checked.

The argument `index` is updated, i.e. this function can be viewed as en decode function that decodes a term into a human readable format.

`int ei_x_format(ei_x_buff* x, const char* fmt, ...)`
`int ei_x_format_wo_ver(ei_x_buff* x, const char *fmt, ... )`

Format a term, given as a string, to a buffer. This functions works like a sprintf for erlang terms. The `fmt` contains a format string, with arguments like `~d`, to insert terms from variables. The following formats are supported (with the C types given):

    ~a - an atom, char*
    ~s - a string, char*
    ~i - an integer, int
    ~l - a long integer, long int
    ~u - a unsigned long integer, unsigned long int
    ~f - a float, float
    ~d - a double float, double float

For instance, to encode a tuple with some stuff:

    ei_x_format("{~a,~i,~d}", "numbers", 12, 3.14159)
    encodes the tuple {numbers,12,3.14159}

The `ei_x_format_wo_ver()` formats into a buffer, without the initial version byte.

`int ei_x_new(ei_x_buff* x)`
`int ei_x_new_with_version(ei_x_buff* x)`

This function allocates a new `ei_x_buff` buffer. The fields of the structure pointed to by `x` parameter is filled in, and a default buffer is allocated. The `ei_x_new_with_version()` also puts an initial version byte, that is used in the binary format. (So that `ei_x_encode_version()` won't be needed.)

`int ei_x_free(ei_x_buff* x)`

This function frees an `ei_x_buff` buffer. The memory used by the buffer is returned to the OS.

`int ei_x_append(ei_x_buff* x, const ei_x_buff* x2)`
`int ei_x_append_buf(ei_x_buff* x, const char* buf, int len)`

These functions appends data at the end of the buffer `x`.

`int ei_skip_term(const char* buf, int* index)`

This function skips a term in the given buffer, it recursively skips elements of lists and tuples, so that a full term is skipped. This is a way to get the size of an erlang term.

`buf` is the buffer.

`index` is updated to point right after the term in the buffer.

| This can be useful when you want to hold arbitrary terms: just skip them and copy the binary term data to some buffer.

The function returns `0` on success and `-1` on failure.

### Debug Information

Some tips on what to check when the emulator doesn't seem to receive the terms that you send.

- be careful with the version header, use `ei_x_new_with_version()` when appropriate
- turn on distribution tracing on the erlang node
- check the result codes from ei_decode_-calls

### See Also

erl_interface(3)

### AUTHORS

Kenneth Lundin - support@erlang.ericsson.se
Jakob Cederlund - support@erlang.ericsson.se

erl_interface 3.4
Copyright © 1991-2003 Ericsson Utvecklings AB