summaryrefslogtreecommitdiff
path: root/doc/ivy-c-3.html
blob: fef73f8a30afc331a5cb5345201854b9796283c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
 <META NAME="GENERATOR" CONTENT="SGML-Tools 1.0.7">
 <TITLE>The Ivy C library guide: Basic functions</TITLE>
 <LINK HREF="ivy-c-4.html" REL=next>
 <LINK HREF="ivy-c-2.html" REL=previous>
 <LINK HREF="ivy-c.html#toc3" REL=contents>
</HEAD>
<BODY>
<A HREF="ivy-c-4.html">Next</A>
<A HREF="ivy-c-2.html">Previous</A>
<A HREF="ivy-c.html#toc3">Contents</A>
<HR>
<H2><A NAME="s3">3. Basic functions</A></H2>

<H2><A NAME="ss3.1">3.1 Initialization and main loop</A>
</H2>

<P>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 <CODE>IvyInit</CODE>. 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 <CODE>IvyStart</CODE>. 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.
<P>The Ivy C library provides its own main loop: <CODE>IvyMainLoop</CODE>. 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 <CODE>IvyMainLoop</CODE>. From within the main loop, you can call <CODE>IvyStop</CODE> to
exit the loop.
<P>Here are more details on those functions:
<P>
<BLOCKQUOTE><CODE>
<PRE>
void IvyInit (const char* agentname,
                        const char* hello_msg,
                        IvyApplicationCallback app_cb,
                        void *app_data,
                        IvyDieCallback die_cb,
                        void *die_data);
</PRE>
</CODE></BLOCKQUOTE>

initializes the library.
<P>
<BLOCKQUOTE><CODE>
<PRE>
void IvyStart (const char* bus);
</PRE>
</CODE></BLOCKQUOTE>

connects your application to the bus specified in <CODE>bus</CODE>. The string provided
should follow the convention described in section XX. Example: <CODE>"127:2010"</CODE>.
<P>
<BLOCKQUOTE><CODE>
<PRE>
void IvyMainLoop (void (*hook) (void));
</PRE>
</CODE></BLOCKQUOTE>

makes your application enter the main loop in which it will handle asynchronous
communications and signals.
<P>
<BLOCKQUOTE><CODE>
<PRE>
void IvyStop ();
</PRE>
</CODE></BLOCKQUOTE>

makes your application exit the main loop.
<P>
<P>
<H2><A NAME="ss3.2">3.2 Emitting messages</A>
</H2>

<P>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 <CODE>IvySendMsg</CODE>, which works like <CODE>printf</CODE>:
<P>
<BLOCKQUOTE><CODE>
<PRE>
void IvySendMsg (const char* format, ...);
</PRE>
</CODE></BLOCKQUOTE>

sends a message on the bus. This function has exactly the same behaviour as
<CODE>printf</CODE>, <CODE>sprintf</CODE> or <CODE>fprintf</CODE>.
<P>
<P>
<H2><A NAME="ss3.3">3.3 Subscribing to messages</A>
</H2>

<P>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 <CODE>main</CODE>. Use function <CODE>IvyBindMsg</CODE> 
to bind a callback to a pattern, and function <CODE>IvyUnbindMsg</CODE> to delete the
binding.
<BLOCKQUOTE><CODE>
<PRE>
MsgRcvPtr IvyBindMsg (MsgCallback cb,
                void* data,
                const char* regex_format, ...);
</PRE>
</CODE></BLOCKQUOTE>

binds callback function <CODE>cb</CODE> to the regular expression specified by
<CODE>regex_format</CODE> and the optional following arguments. <CODE>regex_format</CODE> and
the following arguments are handled as in <CODE>printf</CODE>.
<P>
<BLOCKQUOTE><CODE>
<PRE>
void IvyUnbindMsg (MsgRcvPtr id);
</PRE>
</CODE></BLOCKQUOTE>

deletes the binding specified by <CODE>id</CODE>
<P>
<P>In what precedes, <CODE>MsgRcvPtr</CODE> is an opaque type used to identify bindings,
<CODE>data</CODE> is a user pointer passed to the callback whenever it is called, and
<CODE>Msgcallback</CODE> is defined as follows:
<BLOCKQUOTE><CODE>
<PRE>
typedef void (*MsgCallback)(IvyClientPtr app, void *data, int argc, char **argv);
</PRE>
</CODE></BLOCKQUOTE>
<P>
<P>
<H2><A NAME="ss3.4">3.4 Example</A>
</H2>

<P>The following application connects to an Ivy bus, translates messages <CODE>"Hi
[name]"</CODE> to <CODE>"Bonjour [name]"</CODE>, and quits on message <CODE>"Bye"</CODE>.
<BLOCKQUOTE><CODE>
<PRE>
#include &lt;stdlib.h>
#include &lt;stdio.h>
#include &lt;getopt.h>
#include &lt;ivy.h>
#include &lt;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);
}
</PRE>
</CODE></BLOCKQUOTE>
<P>
<P>
<P>
<P>
<HR>
<A HREF="ivy-c-4.html">Next</A>
<A HREF="ivy-c-2.html">Previous</A>
<A HREF="ivy-c.html#toc3">Contents</A>
</BODY>
</HTML>