New function zwait that waits for a variable change - due to i/o events
[egate.git] / www / wirtcl.c
1 /*
2  * Copyright (c) 1995, the EUROPAGATE consortium (see below).
3  *
4  * The EUROPAGATE consortium members are:
5  *
6  *    University College Dublin
7  *    Danmarks Teknologiske Videnscenter
8  *    An Chomhairle Leabharlanna
9  *    Consejo Superior de Investigaciones Cientificas
10  *
11  * Permission to use, copy, modify, distribute, and sell this software and
12  * its documentation, in whole or in part, for any purpose, is hereby granted,
13  * provided that:
14  *
15  * 1. This copyright and permission notice appear in all copies of the
16  * software and its documentation. Notices of copyright or attribution
17  * which appear at the beginning of any file must remain unchanged.
18  *
19  * 2. The names of EUROPAGATE or the project partners may not be used to
20  * endorse or promote products derived from this software without specific
21  * prior written permission.
22  *
23  * 3. Users of this software (implementors and gateway operators) agree to
24  * inform the EUROPAGATE consortium of their use of the software. This
25  * information will be used to evaluate the EUROPAGATE project and the
26  * software, and to plan further developments. The consortium may use
27  * the information in later publications.
28  * 
29  * 4. Users of this software agree to make their best efforts, when
30  * documenting their use of the software, to acknowledge the EUROPAGATE
31  * consortium, and the role played by the software in their work.
32  *
33  * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
34  * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
35  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
36  * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
37  * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
38  * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
39  * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
40  * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
41  * USE OR PERFORMANCE OF THIS SOFTWARE.
42  *
43  * $Log: wirtcl.c,v $
44  * Revision 1.3  1995/10/30 17:35:18  adam
45  * New function zwait that waits for a variable change - due to i/o events
46  * that invoke callback routines.
47  *
48  * Revision 1.2  1995/10/27  17:30:16  adam
49  * First search request/response that works.
50  *
51  * Revision 1.1  1995/10/27  15:12:08  adam
52  * IrTcl incorporated in the gateway.
53  * Better separation of script types.
54  * Z39.50 gateway scripts entered.
55  *
56  */
57
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <unistd.h>
61 #include <sys/time.h>
62 #include <sys/types.h>
63 #ifdef AIX
64 #include <sys/select.h>
65 #endif
66 #include <string.h>
67 #include <assert.h>
68 #include <ctype.h>
69
70 #include "wtcl.h"
71 #include "wirtcl.h"
72
73 static void *do_create (WCLIENT wcl, void *args);
74 static int do_exec (const char *fname, char *parms, void *mydata);
75
76 static struct w_interp_type w_interp_t = {
77     "irtcl",
78     do_create,
79     do_exec
80 };
81
82 W_Interp_Type w_interp_irtcl = &w_interp_t;
83
84
85 static char *mod = "wirtcl";
86
87 struct tcl_info {
88     W_Interp w_interp;
89     Tcl_Interp *interp;
90     WCLIENT wcl;
91 };
92
93
94 static int events (struct tcl_info *p, char *waitVar);
95
96 static int proc_zwait_invoke (ClientData clientData, Tcl_Interp *interp,
97                               int argc, char **argv)
98 {
99     struct tcl_info *p = (struct tcl_info*) clientData;
100     
101     if (argc < 2)
102         return TCL_OK;
103     events (p, argv[1]);
104     return TCL_OK;
105 }
106
107
108
109 /* select(2) callbacks */
110 struct callback {
111     void (*r_handle)(ClientData);
112     void (*w_handle)(ClientData);
113     void (*x_handle)(ClientData);
114     void *obj;
115 };
116 #define MAX_CALLBACK 200
117
118 static struct callback callback_table[MAX_CALLBACK];
119 static int max_fd = 3;            /* don't worry: it will grow... */
120
121 static void *do_create (WCLIENT wcl, void *args)
122 {
123     struct tcl_info *p;
124     int i;
125
126     if (!(p = malloc (sizeof(*p))))
127     {
128         gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, mod, "malloc: irtcl_info");
129         exit (1);
130     }
131     if (!(p->w_interp = w_interp_create (w_interp_tcl, wcl, NULL)))
132     {
133         gw_log (GW_LOG_FATAL, mod, "Cannot make Tcl_Interp");
134         exit (1);
135     }
136     p->wcl = wcl;
137     p->interp = w_interp_tcl_get (p->w_interp);
138     if (Irtcl_Init(p->interp) == TCL_ERROR)
139     {
140         gw_log (GW_LOG_FATAL, mod, "Cannot make Irtcl_Interp");
141         exit (1);
142     }
143     /* initialize irtcl */
144     Tcl_CreateCommand (p->interp, "zwait", proc_zwait_invoke, p, NULL);
145     for (i=0; i<MAX_CALLBACK; i++)
146     {
147         callback_table[i].r_handle = NULL;
148         callback_table[i].w_handle = NULL;
149         callback_table[i].x_handle = NULL;
150     }
151     return p;
152 }
153
154
155 static int do_exec (const char *fname, char *parms, void *mydata)
156 {
157     struct tcl_info *p = mydata;
158     int r;
159     if ((r = w_interp_exec (p->w_interp, fname, parms)))
160         return r;
161     return 0;
162 }
163
164
165 static int events (struct tcl_info *p, char *waitVar)
166 {
167     int r, i, min_fd = 0;
168     char *cp;
169     char *waitVarVal;
170     static fd_set fdset_tcl_r;
171     static fd_set fdset_tcl_w;
172     static fd_set fdset_tcl_x;
173
174     assert (waitVar);
175     if ((cp = Tcl_GetVar (p->interp, waitVar, 0)))
176     {
177         waitVarVal = malloc (strlen(cp)+1);
178         strcpy (waitVarVal, cp);
179     }
180     else
181     {
182         gw_log (GW_LOG_WARN, mod, "Variable %s doesn't exist", waitVar);
183         return 0;
184     }
185     gw_log (GW_LOG_DEBUG, mod, "Waiting for variable %s=%s",
186             waitVar, waitVarVal);
187     while (1)
188     {
189         if (!(cp = Tcl_GetVar (p->interp, waitVar, 0)) ||
190             strcmp (cp, waitVarVal))
191         {
192             free (waitVarVal);
193             return 0;
194         }
195         FD_ZERO (&fdset_tcl_r);
196         FD_ZERO (&fdset_tcl_w);
197         FD_ZERO (&fdset_tcl_x);
198         
199         for (r=0, i=min_fd; i<=max_fd; i++)
200         {
201             if (callback_table[i].w_handle)
202             {
203                 FD_SET (i, &fdset_tcl_w);
204                 r++;
205             }
206             if (callback_table[i].r_handle)
207             {
208                 FD_SET (i, &fdset_tcl_r);
209                 r++;
210             }
211             if (callback_table[i].x_handle)
212             {
213                 FD_SET (i, &fdset_tcl_x);
214                 r++;
215             }
216         }
217         if (!r)
218             break;
219         if ((r = select(max_fd+1, &fdset_tcl_r, &fdset_tcl_w, 
220                           &fdset_tcl_x, 0)) < 0)
221         {
222             perror("select");
223             exit(1);
224         }
225         if (!r)
226             continue;
227         for (i=min_fd; i<=max_fd; i++)
228         {
229             if (FD_ISSET (i, &fdset_tcl_r))
230             {
231                 assert (callback_table[i].r_handle);
232                 (*callback_table[i].r_handle) (callback_table[i].obj);
233             }
234             if (FD_ISSET (i, &fdset_tcl_w))
235             {
236                 assert (callback_table[i].w_handle);
237                 (*callback_table[i].w_handle) (callback_table[i].obj);
238             }
239             if (FD_ISSET (i, &fdset_tcl_x))
240             {
241                 assert (callback_table[i].x_handle);
242                 (*callback_table[i].x_handle) (callback_table[i].obj);
243             }
244         }
245     }
246     free (waitVarVal);
247     return 0;
248 }
249
250 void ir_select_add (int fd, void *obj)
251 {
252     callback_table[fd].obj = obj;
253     callback_table[fd].r_handle = ir_select_read;
254     callback_table[fd].w_handle = NULL;
255     callback_table[fd].x_handle = NULL;
256     if (fd > max_fd)
257         max_fd = fd;
258 }
259
260 void ir_select_add_write (int fd, void *obj)
261 {
262     callback_table[fd].w_handle = ir_select_write;
263     if (fd > max_fd)
264         max_fd = fd;
265 }
266
267 void ir_select_remove_write (int fd, void *obj)
268 {
269     callback_table[fd].w_handle = NULL;
270 }
271
272 void ir_select_remove (int fd, void *obj)
273 {
274     callback_table[fd].r_handle = NULL;
275     callback_table[fd].w_handle = NULL;
276     callback_table[fd].x_handle = NULL;
277 }