O2 2.0
A communication protocol for interactive music and media applications.
Functions
Low-Level Message Parsing

Functions

int o2_extract_start (o2_msg_data_ptr msg)
 initialize internal state to parse, extract, and coerce message arguments. More...
 
O2arg_ptr o2_get_next (O2type type_code)
 get the next message parameter More...
 

Detailed Description

These functions can retrieve message arguments one-at-a-time. There are some hidden state variables to keep track of the state of unpacking, so these functions are not reentrant. Arguments are returned using a pointer to a union type: #O2arg_ptr.

Function Documentation

◆ o2_extract_start()

int o2_extract_start ( o2_msg_data_ptr  msg)

initialize internal state to parse, extract, and coerce message arguments.

Returns
length of the type string in msg

To get arguments from a message, call o2_extract_start, then for each parameter, call o2_get_next.

get ready to extract args with o2_get_next returns length of type string (not including ',') in message

◆ o2_get_next()

O2arg_ptr o2_get_next ( O2type  to_type)

get the next message parameter

This function is called repeatedly to obtain parameters in order from the message passed to o2_extract_start.

If the message parameter type matches the type_code, a pointer to the parameter is returned. If the types do not match, but coercion is possible, the parameter is coerced, copied to a new location, and a pointer is returned. Otherwise, NULL is returned.

The type of any non-NULL return value always matches the type specified by the parameter type_code. To determine the original type of the parameter as specified by the message, use the types string which is passed to message handlers. (Or course, this assumes that message type strings are correct. Badly formed messages are detected when the type string and data imply that the message is longer than the actual length, but otherwise there is no way to detect errors in type strings.)

The result points into the message or to a statically allocated buffer if type coercion is required. This storage is valid until the next call to o2_extract_start. If the value is a pointer (string, symbol, midi data, blob), then the value was not copied and remains in place within the message, so there should never be the need to immediately copy the data pointed to. However, since the storage for the value is the message, and the message will be freed when the handler returns, pointers to strings, symbols, midi data, and blobs must not be used after the handler returns.

Example 1: Simple but not completely robust

Note: call o2_method_new with type_spec = "id", h = my_handler, coerce = false, parse = false. In this case, since there is no type coercion, type_spec must match the message exactly, so o2_get_next should always return a non-null O2arg_ptr. However, this code can fail if a badly formed message is sent because there is no test for the NULL value that will be returned by o2_get_next.

int my_handler(O2message_ptr msg, char *types,
O2arg_ptr *argv, int argc, void *user_data)
{
// we expect an int32 and a double argument
int32_t my_int = o2_get_next(O2_INT32)->i32;
double my_double = o2_get_next(O2_DOUBLE)->d;
...
}
@ O2_DOUBLE
64 bit IEEE-754 double.
Definition: o2.h:729
@ O2_INT32
32 bit signed integer.
Definition: o2.h:719
int o2_extract_start(o2_msg_data_ptr msg)
initialize internal state to parse, extract, and coerce message arguments.
Definition: message.cpp:869
O2arg_ptr o2_get_next(O2type to_type)
get the next message parameter
Definition: message.cpp:1018
an O2 message container
Definition: o2.h:690
union of all O2 parameter types
Definition: o2.h:764
int32_t i32
32 bit signed integer.
Definition: o2.h:765
double d
64 bit IEEE-754 double.
Definition: o2.h:771

Example 2: Type coercion and type checking.

Note: call o2_method_new with type_spec = NULL, h = my_handler, coerce = false, parse = false. In this case, even though coerce is false, there is no type_spec, so the handler will be called without type checking. We could check the actual message types (given by types), but here, we will coerce into our desired types (int32 and double) if possible. Since type coercion can fail (e.g. string will not be converted to number, not even "123"), we need to check the return value from o2_get_next, where NULL indicates incompatible types.

int my_handler(O2message_ptr msg, char *types,
O2arg_ptr *argv, int argc, void *user_data)
{
// we want to get an int32 and a double argument
if (!ap) return O2_FAIL; // parameter cannot be coerced
int32_t my_int = ap->i32;
if (!ap) return O2_FAIL; // parameter cannot be coerced
double my_double = ap->d;
...
}
@ O2_FAIL
a non-specific error occurred.
Definition: o2.h:339
Parameters
type_codethe desired parameter type
Returns
the next message parameter or NULL if no more parameters

get the next argument from the message. If the to_type does not match the actual type in the message, convert if possible; otherwise, return NULL for the O2arg_ptr. Note that if coerce_flag was false, the type checking will have compared types for an exact match, so if we make it this far and we are constructing argv, then no type coercion will take place (and the tests for type matching are all redundant because they will all fail). If client code is calling this, then there is no way to turn off type coercion except that you can compare your desired to_type to the character in the actual type string and if there is no match, do not call o2_get_next().