Initializing an Ivy agent with the Ivy C library is a two-step process. First of
all, you should initialize the library by calling function IvyInit
. Once
the library is initialized you can create timers and add subscriptions, but your
agent is still not connected to any bus. In order to connect, you should call
function IvyStart
. In theory, initialization is then over. However in
practice, as for any asynchronous communication or interaction library, nothing
happens until your application has reached the main loop.
The Ivy C library provides its own main loop: IvyMainLoop
. You should use
it unless you already use a toolkit that provides its own main loop and you want
to use that one. If it is the case, please refer to section XX. Otherwise, just
call IvyMainLoop
. From within the main loop, you can call IvyStop
to
exit the loop.
Here are more details on those functions:
void IvyInit (const char* agentname,
const char* hello_msg,
IvyApplicationCallback app_cb,
void *app_data,
IvyDieCallback die_cb,
void *die_data);
initializes the library.
void IvyStart (const char* bus);
connects your application to the bus specified in bus
. The string provided
should follow the convention described in section XX. Example: "127:2010"
.
void IvyMainLoop (void (*hook) (void));
makes your application enter the main loop in which it will handle asynchronous
communications and signals.
void IvyStop ();
makes your application exit the main loop.
Emitting a message on an Ivy bus is much like printing a message on the standard
output. However, do not forget that your message will not be emitted if Ivy has
not been properly initialized and if you do not have a main loop of some sort
running. To emit a message, use IvySendMsg
, which works like printf
:
void IvySendMsg (const char* format, ...);
sends a message on the bus. This function has exactly the same behaviour as
printf
, sprintf
or fprintf
.
Subscribing to messages consists in binding a callback function to a message
pattern. Patterns are described by regular expressions with captures. When a
message matching the regular expression is detected on the bus, the callback
function is called. The captures (ie the bits of the message that match the
parts of regular expression delimited by brackets) are passed to the callback
function much like options are passed to main
. Use function IvyBindMsg
to bind a callback to a pattern, and function IvyUnbindMsg
to delete the
binding.
MsgRcvPtr IvyBindMsg (MsgCallback cb,
void* data,
const char* regex_format, ...);
binds callback function cb
to the regular expression specified by
regex_format
and the optional following arguments. regex_format
and
the following arguments are handled as in printf
.
void IvyUnbindMsg (MsgRcvPtr id);
deletes the binding specified by id
In what precedes, MsgRcvPtr
is an opaque type used to identify bindings,
data
is a user pointer passed to the callback whenever it is called, and
Msgcallback
is defined as follows:
typedef void (*MsgCallback)(IvyClientPtr app, void *data, int argc, char **argv);
The following application connects to an Ivy bus, translates messages "Hi
[name]"
to "Bonjour [name]"
, and quits on message "Bye"
.
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include <ivy.h>
#include <ivyloop.h>
/* callback associated to "Hi" messages */
void HiCallback (IvyClientPtr app, void *data, int argc, char **argv)
{
if (argc != 1)
fprintf (stderr, "wrong format!\n");
else
IvySendMsg ("Bonjour %s", argv[0]);
}
void ByeCallback (IvyClientPtr app, void *data, int argc, char **argv)
{
IvyStop ();
}
main (int argc, char**argv)
{
/* handling of -b option */
const char* bus = 0;
char c;
while (c = getopt (argc, argv, "b:") != EOF) {
switch (c) {
case 'b':
bus = optarg;
break;
}
}
/* handling of environment variable */
if (!bus)
bus = getenv ("IVYBUS");
/* initializations */
IvyInit ("MagicTranslater", "Hello le monde", 0, 0, 0, 0);
IvyStart (bus);
/* bindings */
IvyBindMsg (HiCallback, 0, "^Hi (.*)");
IvyBindMsg (ByeCallback, 0, "^Bye$");
/* main loop */
IvyMainLoop (0);
}