Simplified select handling. Only one function ir_tcl_select_set has
[ir-tcl-moved-to-github.git] / tclmain.c
1 /*
2  * IR toolkit for tcl/tk
3  * (c) Index Data 1995
4  * See the file LICENSE for details.
5  * Sebastian Hammer, Adam Dickmeiss
6  *
7  * $Log: tclmain.c,v $
8  * Revision 1.17  1996-02-21 10:16:21  adam
9  * Simplified select handling. Only one function ir_tcl_select_set has
10  * to be externally defined.
11  *
12  * Revision 1.16  1996/02/05  17:58:05  adam
13  * Ported ir-tcl to use the beta releases of tcl7.5/tk4.1.
14  *
15  * Revision 1.15  1996/01/10  09:18:45  adam
16  * PDU specific callbacks implemented: initRespnse, searchResponse,
17  *  presentResponse and scanResponse.
18  * Bug fix in the command line shell (tclmain.c) - discovered on OSF/1.
19  *
20  * Revision 1.14  1995/09/21  13:11:53  adam
21  * Support of dynamic loading.
22  * Test script uses load command if necessary.
23  *
24  * Revision 1.13  1995/08/28  12:21:22  adam
25  * Removed lines and list as synonyms of list in MARC extractron.
26  * Configure searches also for tk4.0 / tcl7.4.
27  *
28  * Revision 1.12  1995/08/28  11:07:16  adam
29  * Minor changes.
30  *
31  * Revision 1.11  1995/08/03  13:23:02  adam
32  * Request queue.
33  *
34  * Revision 1.10  1995/06/30  12:39:28  adam
35  * Bug fix: loadFile didn't set record type.
36  * The MARC routines are a little less strict in the interpretation.
37  * Script display.tcl replaces the old marc.tcl.
38  * New interactive script: shell.tcl.
39  *
40  * Revision 1.9  1995/06/26  10:20:20  adam
41  * ir-tk works like wish.
42  *
43  * Revision 1.8  1995/06/21  15:16:44  adam
44  * More work on configuration.
45  *
46  * Revision 1.7  1995/06/21  11:04:54  adam
47  * Uses GNU autoconf 2.3.
48  * Install procedure implemented.
49  * boook bitmaps moved to sub directory bitmaps.
50  *
51  * Revision 1.6  1995/05/29  08:44:28  adam
52  * Work on delete of objects.
53  *
54  * Revision 1.5  1995/03/20  08:53:30  adam
55  * Event loop in tclmain.c rewritten. New method searchStatus.
56  *
57  * Revision 1.4  1995/03/17  07:50:31  adam
58  * Headers have changed a little.
59  *
60  */
61
62 #include <unistd.h>
63 #include <sys/time.h>
64 #include <sys/types.h>
65 #ifdef _AIX
66 #include <sys/select.h>
67 #endif
68 #include <assert.h>
69
70 #include <tcl.h>
71 #include <log.h>
72 #include "ir-tcl.h"
73
74 static char *fileName = NULL;
75
76 /* select(2) callbacks */
77 struct callback {
78     void (*handle)(ClientData, int, int, int);
79     int r, w, e;
80     ClientData obj;
81 };
82 #define MAX_CALLBACK 200
83
84 static struct callback callback_table[MAX_CALLBACK];
85 static int max_fd = 3;            /* don't worry: it will grow... */
86
87 void tcl_mainloop (Tcl_Interp *interp, int interactive);
88
89 int Tcl_AppInit (Tcl_Interp *interp)
90 {
91     if (Tcl_Init(interp) == TCL_ERROR)
92         return TCL_ERROR;
93     if (Irtcl_Init(interp) == TCL_ERROR)
94         return TCL_ERROR;
95     return TCL_OK;
96 }
97
98 int main (int argc, char **argv)
99 {
100     Tcl_Interp *interp;
101     int code;
102     int i;
103
104     interp = Tcl_CreateInterp();
105     Tcl_SetVar (interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY);
106     if (argc == 2)
107         fileName = argv[1];
108
109     if (Tcl_AppInit(interp) != TCL_OK) {
110         fprintf(stderr, "Tcl_AppInit failed: %s\n", interp->result);
111     }
112     for (i=0; i<MAX_CALLBACK; i++)
113         callback_table[i].handle = NULL;
114     if (fileName)
115     {
116         code = Tcl_EvalFile (interp, fileName);
117         if (*interp->result != 0)
118             printf ("%s\n", interp->result);
119         if (code != TCL_OK)
120             exit (1);
121         tcl_mainloop (interp, 0);
122     }
123     else if (isatty(0))
124     {
125
126         Tcl_SetVar (interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY);
127         tcl_mainloop (interp, 1);
128     }
129     else
130     {
131         Tcl_DString command;
132         char input_buf[1024];
133         int count;
134
135         printf ("xx\n");
136         Tcl_DStringInit (&command);
137         while (fgets (input_buf, 1024, stdin))
138         {
139             count = strlen(input_buf);
140             Tcl_DStringAppend (&command, input_buf, count);
141             if (Tcl_CommandComplete (Tcl_DStringValue (&command)))
142             {
143                 int code = Tcl_Eval (interp, Tcl_DStringValue (&command));
144                 Tcl_DStringFree (&command);
145                 if (code)
146                     printf ("Error: %s\n", interp->result);
147             }
148         }
149         tcl_mainloop (interp, 0);
150     }
151     exit (0);
152 }
153
154 void tcl_mainloop (Tcl_Interp *interp, int interactive)
155 {
156     int i;
157     int res;
158     Tcl_DString command;
159     static fd_set fdset_tcl_r;
160     static fd_set fdset_tcl_w;
161     static fd_set fdset_tcl_x;
162     int min_fd;
163
164     min_fd = interactive ? 3 : 0;
165     if (interactive)
166     {
167         Tcl_DStringInit (&command);
168         printf ("%% "); fflush (stdout);
169     }
170     while (1)
171     {
172         FD_ZERO (&fdset_tcl_r);
173         FD_ZERO (&fdset_tcl_w);
174         FD_ZERO (&fdset_tcl_x);
175         if (interactive)
176             FD_SET (0, &fdset_tcl_r);
177         for (res=0, i=min_fd; i<=max_fd; i++)
178         {
179             if (callback_table[i].handle && callback_table[i].w)
180             {
181                 FD_SET (i, &fdset_tcl_w);
182                 res++;
183             }
184             if (callback_table[i].handle && callback_table[i].r)
185             {
186                 FD_SET (i, &fdset_tcl_r);
187                 res++;
188             }
189             if (callback_table[i].handle && callback_table[i].e)
190             {
191                 FD_SET (i, &fdset_tcl_x);
192                 res++;
193             }
194         }
195         if (!interactive && !res)
196             return;
197         if ((res = select(max_fd+1, &fdset_tcl_r, &fdset_tcl_w, 
198                           &fdset_tcl_x, 0)) < 0)
199         {
200             perror("select");
201             exit(1);
202         }
203         if (!res)
204             continue;
205         for (i=min_fd; i<=max_fd; i++)
206         {
207             int r_flag = 0;
208             int w_flag = 0;
209             int e_flag = 0;
210
211             if (!callback_table[i].handle)
212                 continue;
213             if (FD_ISSET (i, &fdset_tcl_r) && callback_table[i].r)
214                 r_flag = 1;
215             if (FD_ISSET (i, &fdset_tcl_w) && callback_table[i].w)
216                 w_flag = 1;
217             if (FD_ISSET (i, &fdset_tcl_x) && callback_table[i].e)
218                 e_flag = 1;
219             if (r_flag || w_flag || e_flag)
220                 (*callback_table[i].handle)(callback_table[i].obj,
221                  r_flag, w_flag, e_flag);
222         }
223         if (interactive && FD_ISSET(0, &fdset_tcl_r))
224         {
225             char input_buf[1024];
226             int count = read (0, input_buf, 1024);
227
228             if (count <= 0)
229                 exit (0);
230             Tcl_DStringAppend (&command, input_buf, count);
231             if (Tcl_CommandComplete (Tcl_DStringValue (&command)))
232             {
233                 int code = Tcl_Eval (interp, Tcl_DStringValue (&command));
234                 Tcl_DStringFree (&command);
235                 if (code)
236                     printf ("Error: %s\n", interp->result);
237                 else if (*interp->result)
238                     printf ("%s\n", interp->result);
239                 printf ("%% "); fflush (stdout);
240             }
241         }
242     }
243 }
244
245 void ir_tcl_select_set (void (*f)(ClientData clientData, int r, int w, int e),
246                         int fd, ClientData clientData, int r, int w, int e)
247 {
248     callback_table[fd].handle = f;
249     callback_table[fd].obj = clientData;
250     callback_table[fd].r = r;
251     callback_table[fd].w = w;
252     callback_table[fd].e = e;
253     if (fd > max_fd)
254         max_fd = fd;
255 }
256