Loading...
Searching...
No Matches
Low-Level Message Parsing

## Functions

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

## 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: o2_arg_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().

## o2_get_next()

o2_arg_ptr o2_get_next | ( | o2_type | type_code | ) |

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 o2_arg_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(o2_message_ptr msg, char *types,
o2_arg_ptr *argv, int argc, void *user_data)
{
o2_extract_start(msg);
// 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
@ O2_DOUBLE
64 bit IEEE-754 double.
Definition o2.h:498
O2_INT32
@ O2_INT32
32 bit signed integer.
Definition o2.h:488
o2_extract_start
int o2_extract_start(o2_msg_data_ptr msg)
initialize internal state to parse, extract, and coerce message arguments.
o2_get_next
o2_arg_ptr o2_get_next(o2_type type_code)
get the next message parameter
o2_message
an O2 message container
Definition o2.h:456
o2_arg
union of all O2 parameter types
Definition o2.h:533
o2_arg::d
double d
64 bit IEEE-754 double.
Definition o2.h:540
o2_arg::i32
int32_t i32
32 bit signed integer.
Definition o2.h:534

### 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(o2_message_ptr msg, char *types,
o2_arg_ptr *argv, int argc, void *user_data)
{
o2_extract_start(msg);
// we want to get an int32 and a double argument
o2_arg_ptr ap = o2_get_next(O2_INT32);
if (!ap) return O2_FAIL; // parameter cannot be coerced
int32_t my_int = ap->i32;
o2_arg_ptr ap = o2_get_next(O2_DOUBLE);
if (!ap) return O2_FAIL; // parameter cannot be coerced
double my_double = ap->d;
...
}
O2_FAIL
#define O2_FAIL
an error return value: a non-specific error occurred.
Definition o2.h:177

Parameters

  type_code | the desired parameter type

Returns
  the next message parameter or NULL if no more parameters