1/* BEGIN LICENSE BLOCK
2 * Version: CMPL 1.1
3 *
4 * The contents of this file are subject to the Cisco-style Mozilla Public
5 * License Version 1.1 (the "License"); you may not use this file except
6 * in compliance with the License.  You may obtain a copy of the License
7 * at www.eclipse-clp.org/license.
8 *
9 * Software distributed under the License is distributed on an "AS IS"
10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11 * the License for the specific language governing rights and limitations
12 * under the License.
13 *
14 * The Original Code is  The ECLiPSe Constraint Logic Programming System.
15 * The Initial Developer of the Original Code is  Cisco Systems, Inc.
16 * Portions created by the Initial Developer are
17 * Copyright (C) 1997-2006 Cisco Systems, Inc.  All Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * END LICENSE BLOCK */
22
23/*
24 *      System: Eclipse
25 *
26 *	$Id: tkeclipse.c,v 1.4 2013/04/17 01:34:20 jschimpf Exp $
27 *
28 *	Code for embedding eclipse into a tcl program
29 */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <errno.h>
34#include <signal.h>
35#include <string.h>
36
37#include <tcl.h>
38#include "eclipse.h"
39
40#include "tkcommon.h"
41
42#ifdef __STDC__
43int EcInit(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
44int EcCleanup(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
45int EcSetOption(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
46int EcPostString(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
47int EcPostGoal(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
48int EcPostEvent(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
49int EcResume(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
50int EcRunning(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
51int EcResumeStatus(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
52int EcHandleEvents(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
53int EcQueueWrite(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
54int EcQueueRead(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
55int EcQueueOpen(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
56int EcStreamNr(ClientData, Tcl_Interp *, int, Tcl_Obj *CONST []);
57#endif
58
59
60/*---------------------------------------------------------------------------
61 * ec_init
62 * ec_cleanup
63 *---------------------------------------------------------------------------*/
64
65int
66EcInit(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
67{
68    if (objc != 1)
69    {
70	Tcl_WrongNumArgs(interp, 1, objv, "");
71	return TCL_ERROR;
72    }
73    if (ec_init() != PSUCCEED)
74    {
75	Tcl_SetResult(interp, "couldn't initialize ECLiPSe", TCL_STATIC);
76	return TCL_ERROR;
77    }
78    return TCL_OK;
79}
80
81int
82EcCleanup(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
83{
84    if (objc != 1)
85    {
86	Tcl_WrongNumArgs(interp, 1, objv, "");
87	return TCL_ERROR;
88    }
89    ec_cleanup();
90    return TCL_OK;
91}
92
93/*---------------------------------------------------------------------------
94 * ec_set_option option_name option_val
95 *---------------------------------------------------------------------------*/
96
97int
98EcSetOption(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
99{
100    long option_id;
101    uword option_val;
102    int err;
103
104    if (objc != 3)
105    {
106	Tcl_WrongNumArgs(interp, 1, objv, "option_name option_value");
107	return TCL_ERROR;
108    }
109    err = Tcl_GetLongFromObj(interp, objv[1], &option_id);
110    if (err != TCL_OK)
111    {
112	char *option_name = Tcl_GetStringFromObj(objv[1], NULL);
113	Tcl_ResetResult(interp);
114	if (!strcmp(option_name, "localsize")) option_id = EC_OPTION_LOCALSIZE;
115	else if (!strcmp(option_name, "globalsize")) option_id = EC_OPTION_GLOBALSIZE;
116	else if (!strcmp(option_name, "privatesize")) option_id = EC_OPTION_PRIVATESIZE;
117	else if (!strcmp(option_name, "sharedsize")) option_id = EC_OPTION_SHAREDSIZE;
118	else if (!strcmp(option_name, "default_module")) option_id = EC_OPTION_DEFAULT_MODULE;
119	else if (!strcmp(option_name, "default_language")) option_id = EC_OPTION_DEFAULT_LANGUAGE;
120	else if (!strcmp(option_name, "eclipsedir")) option_id = EC_OPTION_ECLIPSEDIR;
121	else if (!strcmp(option_name, "io")) option_id = EC_OPTION_IO;
122	else if (!strcmp(option_name, "cwd_separate")) option_id = EC_OPTION_CWD_SEPARATE;
123	else {
124	    Tcl_SetResult(interp, "invalid option name", TCL_STATIC);
125	    return TCL_ERROR;
126	}
127    }
128    err = ec_set_option_ptr(option_id, NULL);
129    if (err == PSUCCEED)	/* it's a valid string option */
130    {
131	char *s = Tcl_GetStringFromObj(objv[2], NULL);
132	(void) ec_set_option_ptr(option_id, strcpy(Tcl_Alloc(strlen(s)+1), s));
133    }
134    else			/* it must be an integer option */
135    {
136#if (SIZEOF_LONG == SIZEOF_CHAR_P)
137	err = Tcl_GetLongFromObj(interp, objv[2], (long *)&option_val);
138#elif (SIZEOF_CHAR_P == __SIZEOF_LONG_LONG__)
139	/* assumes Tcl_WideInt is same size as word */
140	err = Tcl_GetWideIntFromObj(interp, objv[2], (Tcl_WideInt *)&option_val);
141#else
142    PROBLEM: cannot deal with this word size
143#endif
144	if (err != TCL_OK)
145	{
146	    Tcl_SetResult(interp, "integer expected", TCL_STATIC);
147	    return TCL_ERROR;
148	}
149	err = ec_set_option_long(option_id, option_val);
150	if (err != PSUCCEED)
151	{
152	    Tcl_SetResult(interp, "invalid option number", TCL_STATIC);
153	    return TCL_ERROR;
154	}
155    }
156    return TCL_OK;
157}
158
159/*---------------------------------------------------------------------------
160 * ec_post_event event_string
161 *---------------------------------------------------------------------------*/
162
163int
164EcPostEvent(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
165{
166    if (objc != 2)
167    {
168	Tcl_WrongNumArgs(interp, 1, objv, "event_string");
169	return TCL_ERROR;
170    }
171    if (ec_post_event_string(Tcl_GetStringFromObj(objv[1], NULL)) != PSUCCEED)
172    {
173	Tcl_SetResult(interp, "could not post event to ECLiPSe", TCL_STATIC);
174	return TCL_ERROR;
175    }
176    return TCL_OK;
177}
178
179
180/*---------------------------------------------------------------------------
181 * ec_resume
182 *---------------------------------------------------------------------------*/
183
184int
185EcResume(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
186{
187    int async, res;
188    long arg = 0;
189    Tcl_Obj *obj;
190
191    if (objc == 1)
192    {
193	async = 0;
194    }
195    else if (objc == 2)
196    {
197	int res = Tcl_GetBooleanFromObj(interp, objv[1], &async);
198	if (res != TCL_OK) {
199	    Tcl_SetResult(interp, "ec_resume_: boolean expected", TCL_STATIC);
200	    return TCL_ERROR;
201	}
202    }
203    else
204    {
205	Tcl_WrongNumArgs(interp, 1, objv, "?async?");
206	return TCL_ERROR;
207    }
208    /* ec_resume_async() can only return PSUCCEED, PRUNNING or SYS_ERROR */
209    res =  async ? ec_resume_async() : ec_resume_long(&arg);
210    switch (res)
211    {
212    case PSUCCEED:
213	Tcl_SetResult(interp, "success", TCL_STATIC);
214	return TCL_OK;
215    case PFAIL:
216	Tcl_SetResult(interp, "fail", TCL_STATIC);
217	return TCL_OK;
218    case PTHROW:
219	Tcl_SetResult(interp, "throw", TCL_STATIC);
220	return TCL_OK;
221    case PRUNNING:
222	Tcl_SetResult(interp, "running", TCL_STATIC);
223	return TCL_OK;
224    case PYIELD:
225	obj = Tcl_NewStringObj("yield", -1);
226	break;
227    case PWAITIO:
228	obj = Tcl_NewStringObj("waitio", -1);
229	break;
230    case PFLUSHIO:
231	obj = Tcl_NewStringObj("flushio", -1);
232	break;
233    default:
234	Tcl_SetResult(interp, async
235		? "could not start ECLiPSe thread in ec_resume_async()"
236		: "unrecognized return code from ec_resume()", TCL_STATIC);
237	return TCL_ERROR;
238    }
239    Tcl_ListObjAppendElement(interp, obj, Tcl_NewLongObj(arg));
240    Tcl_SetObjResult(interp, obj);
241    return TCL_OK;
242}
243
244
245/*---------------------------------------------------------------------------
246 * ec_handle_events
247 * Ignore posted goals, don't continue -> only handle events
248 * Event handlers must not fail, throw or yield.
249 * Allowed is only success, waitio, flushio.
250 * In case of previous ec_resume_async we may also still be running.
251 *---------------------------------------------------------------------------*/
252
253int
254EcHandleEvents(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
255{
256    long arg;
257    Tcl_Obj *obj;
258    int res;
259
260    if (objc != 1)
261    {
262	Tcl_WrongNumArgs(interp, 1, objv, "");
263	return TCL_ERROR;
264    }
265
266    res = ec_handle_events(&arg);
267    switch (res)
268    {
269    case PRUNNING:
270	Tcl_SetResult(interp, "running", TCL_STATIC);
271	return TCL_OK;
272    case PSUCCEED:
273	Tcl_SetResult(interp, "success", TCL_STATIC);
274	return TCL_OK;
275    case PWAITIO:
276	obj = Tcl_NewStringObj("waitio", -1);
277	break;
278    case PFLUSHIO:
279	obj = Tcl_NewStringObj("flushio", -1);
280	break;
281
282    case PFAIL:
283	Tcl_SetResult(interp, "fail", TCL_STATIC);
284	return TCL_ERROR;
285    case PTHROW:
286	Tcl_SetResult(interp, "throw", TCL_STATIC);
287	return TCL_ERROR;
288    case PYIELD:
289	Tcl_SetResult(interp, "yield", TCL_STATIC);
290	return TCL_ERROR;
291    default:
292	Tcl_SetResult(interp, "unrecognized return code from ec_handle_events()", TCL_STATIC);
293	return TCL_ERROR;
294    }
295    Tcl_ListObjAppendElement(interp, obj, Tcl_NewLongObj(arg));
296    Tcl_SetObjResult(interp, obj);
297    return TCL_OK;
298}
299
300
301/*---------------------------------------------------------------------------
302 * ec_running
303 * returns a boolean indicating whether an eclipse thread is running.
304 *---------------------------------------------------------------------------*/
305
306int
307EcRunning(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
308{
309    if (objc != 1)
310    {
311	Tcl_WrongNumArgs(interp, 1, objv, "");
312	return TCL_ERROR;
313    }
314    Tcl_SetObjResult(interp, Tcl_NewBooleanObj(ec_running()));
315    return TCL_OK;
316}
317
318/*---------------------------------------------------------------------------
319 * ec_resume_status ?timeout?
320 * returns (again) the status of the last ec_resume or ec_handle_events
321 *---------------------------------------------------------------------------*/
322
323int
324EcResumeStatus(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
325{
326    long arg;
327    Tcl_Obj *obj;
328    int timeout;
329    int err;
330
331    if (objc == 1)
332    {
333	timeout = 0;
334    }
335    else if (objc == 2)
336    {
337	err = Tcl_GetIntFromObj(interp, objv[1], &timeout);
338	if (err != TCL_OK)
339	{
340	    Tcl_SetResult(interp, "ec_resume_status: integer expected", TCL_STATIC);
341	    return TCL_ERROR;
342	}
343    }
344    else
345    {
346	Tcl_WrongNumArgs(interp, 1, objv, "?timeout?");
347	return TCL_ERROR;
348    }
349    switch (ec_wait_resume_status_long(&arg, timeout))
350    {
351    case PSUCCEED:
352	Tcl_SetResult(interp, "success", TCL_STATIC);
353	return TCL_OK;
354    case PFAIL:
355	Tcl_SetResult(interp, "fail", TCL_STATIC);
356	return TCL_OK;
357    case PTHROW:
358	Tcl_SetResult(interp, "throw", TCL_STATIC);
359	return TCL_OK;
360    case PRUNNING:
361	Tcl_SetResult(interp, "running", TCL_STATIC);
362	return TCL_OK;
363    case PYIELD:
364	obj = Tcl_NewStringObj("yield", -1);
365	break;
366    case PWAITIO:
367	obj = Tcl_NewStringObj("waitio", -1);
368	break;
369    case PFLUSHIO:
370	obj = Tcl_NewStringObj("flushio", -1);
371	break;
372    default:
373	Tcl_SetResult(interp, "unrecognized return code from ec_resume_status()", TCL_STATIC);
374	return TCL_ERROR;
375    }
376    Tcl_ListObjAppendElement(interp, obj, Tcl_NewLongObj(arg));
377    Tcl_SetObjResult(interp, obj);
378    return TCL_OK;
379}
380
381/*---------------------------------------------------------------------------
382 * read/write directly from/to ECLiPSe queue
383 *---------------------------------------------------------------------------*/
384
385int
386EcQueueWrite(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
387{
388    int stream_nr, len;
389    char *s;
390    int err;
391
392    if (objc != 3)
393    {
394	Tcl_WrongNumArgs(interp, 1, objv, "eclipse_name data");
395	return TCL_ERROR;
396    }
397
398    /* get the eclipse stream number, objv[1] is number or string */
399    err = Tcl_GetIntFromObj(interp, objv[1], &stream_nr);
400    if (err != TCL_OK)
401    {
402	stream_nr = ec_stream_nr(Tcl_GetStringFromObj(objv[1], NULL));
403	if (stream_nr < 0)
404	{
405	    Tcl_SetResult(interp, "ec_queue_write: no such ECLiPSe stream", TCL_STATIC);
406	    return TCL_ERROR;
407	}
408	Tcl_ResetResult(interp);
409    }
410    s = Tcl_GetByteArrayFromObj(objv[2], &len);
411    if (ec_queue_write(stream_nr, s, len) < 0)
412    {
413	Tcl_SetResult(interp, "ec_queue_write: cannot write ECLiPSe stream", TCL_STATIC);
414	return TCL_ERROR;
415    }
416    return TCL_OK;
417}
418
419int
420EcQueueRead(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
421{
422    Tcl_Obj *result;
423    int stream_nr, len;
424    int err;
425
426    if (objc != 3)
427    {
428	Tcl_WrongNumArgs(interp, 1, objv, "eclipse_name size");
429	return TCL_ERROR;
430    }
431
432    /* get the eclipse stream number, objv[1] is number or string */
433    err = Tcl_GetIntFromObj(interp, objv[1], &stream_nr);
434    if (err != TCL_OK)
435    {
436	stream_nr = ec_stream_nr(Tcl_GetStringFromObj(objv[1], NULL));
437	if (stream_nr < 0)
438	{
439	    Tcl_SetResult(interp, "ec_queue_read: no such ECLiPSe stream", TCL_STATIC);
440	    return TCL_ERROR;
441	}
442	Tcl_ResetResult(interp);
443    }
444    err = Tcl_GetIntFromObj(interp, objv[2], &len);
445    if (err != TCL_OK)
446    {
447	Tcl_SetResult(interp, "ec_queue_read: integer expected", TCL_STATIC);
448	return TCL_ERROR;
449    }
450    result = Tcl_NewObj();
451    len = ec_queue_read(stream_nr, Tcl_SetByteArrayLength(result,len), len);
452    if (len < 0)
453    {
454	interp->result = "ec_queue_read: cannot read from ECLiPSe stream";
455	return TCL_ERROR;
456    }
457    Tcl_SetByteArrayLength(result, len);
458    Tcl_SetObjResult(interp, result);
459    return TCL_OK;
460}
461
462
463/*---------------------------------------------------------------------------
464 * Channel driver: mapping ECLiPSe streams to TCL channels
465 *---------------------------------------------------------------------------*/
466
467static int EcStreamClose(ClientData, Tcl_Interp *);
468static int EcStreamInput(ClientData, char *, int, int *);
469static int EcStreamOutput(ClientData, const char *, int, int *);
470static void EcStreamWatch(ClientData, int);
471static int EcStreamGetHandle(ClientData, int, ClientData *);
472
473/*ARGSUSED*/
474static int
475EcStreamClose(ClientData nst, Tcl_Interp *interp)
476{
477    return 0;
478}
479
480static int
481EcStreamInput(ClientData stream_nr, char *buf, int size, int *err)
482{
483    int nread;
484    nread = ec_queue_read((int)(word)stream_nr, buf, size);
485    if (nread < 0)
486    {
487	*err = EIO;
488    	return -1;
489    }
490    return nread;
491}
492
493static int
494EcStreamOutput(ClientData stream_nr, const char *buf, int size, int *err)
495{
496    int nread;
497    nread = ec_queue_write((int)(word)stream_nr, (char *) buf, size);
498    if (nread < 0)
499    {
500	*err = EIO;
501    	return -1;
502    }
503    return nread;
504}
505
506/*ARGSUSED*/
507static void
508EcStreamWatch(ClientData stream_nr, int mask)
509{
510}
511
512/*ARGSUSED*/
513static int
514EcStreamGetHandle(ClientData stream_nr, int direction, ClientData *handlePtr)
515{
516    return TCL_ERROR;
517}
518
519
520Tcl_ChannelType ec_stream_channel = {
521    	"eclipse_stream",
522	NULL,
523	EcStreamClose,
524	EcStreamInput,
525	EcStreamOutput,
526	NULL,
527	NULL,
528	NULL,
529	EcStreamWatch,
530	EcStreamGetHandle
531    };
532
533
534/*---------------------------------------------------------------------------
535 * ec_queue_open eclipse_name access
536 *---------------------------------------------------------------------------*/
537
538int
539EcQueueOpen(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
540{
541    int stream_nr, mask;
542    char *accessvar;
543    char mode;
544    Tcl_Channel channel;
545    char channelName[16];
546    int err;
547
548    if (objc != 3)
549    {
550	Tcl_WrongNumArgs(interp, 1, objv, "eclipse_name access_mode");
551	return TCL_ERROR;
552    }
553
554    /* get the eclipse stream number, objv[1] is number or string */
555    err = Tcl_GetIntFromObj(interp, objv[1], &stream_nr);
556    if (err != TCL_OK)
557    {
558	stream_nr = ec_stream_nr(Tcl_GetStringFromObj(objv[1], NULL));
559	if (stream_nr < 0)
560	{
561	    Tcl_SetResult(interp, "no such ECLiPSe stream", TCL_STATIC);
562	    return TCL_ERROR;
563	}
564    }
565
566    accessvar = Tcl_GetStringFromObj(objv[2], NULL);
567    /* convert fromec to r, toec to w */
568    if (strcmp(accessvar, "fromec\0") == 0 || strcmp(accessvar, "r\0") == 0)
569    {
570       mode = 'r';
571    } else if (strcmp(accessvar, "toec\0") == 0 || strcmp(accessvar, "w\0") == 0)
572    {
573       mode = 'w';
574    } else {
575	Tcl_SetResult(interp, "arg 2: fromec (r) or toec (w) expected", TCL_STATIC);
576	return TCL_ERROR;
577    }
578    mask = (mode == 'r') ? TCL_READABLE : TCL_WRITABLE;
579
580    sprintf(channelName, "ec_queue%d", stream_nr);
581    if (Tcl_GetChannel(interp, channelName, NULL) != NULL)
582    {
583	Tcl_SetResult(interp, "channel name exists already", TCL_STATIC);
584	return TCL_ERROR;
585    }
586    channel = Tcl_CreateChannel(&ec_stream_channel, channelName,
587    			(ClientData)(word)stream_nr, mask);
588    if (!channel)
589    {
590	Tcl_SetResult(interp, "couldn't create channel", TCL_STATIC);
591	return TCL_ERROR;
592    }
593    (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) channel,
594    	"-translation", "binary");
595    (void) Tcl_SetChannelOption(NULL, (Tcl_Channel) channel,
596    	"-buffering", "none");
597    Tcl_RegisterChannel(interp, channel);
598    Tcl_SetObjResult(interp, Tcl_NewStringObj(channelName, -1));
599    return TCL_OK;
600}
601
602
603/*---------------------------------------------------------------------------
604 * ec_stream_nr stream_name
605 *---------------------------------------------------------------------------*/
606
607int
608EcStreamNr(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
609{
610    int err, stream_nr;
611
612    if (objc != 2)
613    {
614	Tcl_WrongNumArgs(interp, 1, objv, "stream_name");
615	return TCL_ERROR;
616    }
617    err = Tcl_GetIntFromObj(interp, objv[1], &stream_nr);
618    if (err != TCL_OK)
619    {
620	stream_nr = ec_stream_nr(Tcl_GetStringFromObj(objv[1], NULL));
621    }
622    if (stream_nr < 0)
623    {
624	Tcl_SetResult(interp, "no such ECLiPSe stream", TCL_STATIC);
625	return TCL_ERROR;
626    }
627    Tcl_SetObjResult(interp, Tcl_NewIntObj(stream_nr));
628    return TCL_OK;
629
630}
631
632
633/*---------------------------------------------------------------------------
634 * ec_post_goal goal ?format?
635 *---------------------------------------------------------------------------*/
636
637int
638EcPostGoal(ClientData clientdata, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv)
639{
640    char *exdr_string;
641    int len;
642    int res = EcTcl2Exdr(clientdata, interp, objc, objv);
643    if (res != TCL_OK)
644    	return res;
645    exdr_string = Tcl_GetByteArrayFromObj(Tcl_GetObjResult(interp), &len);
646    ec_post_exdr(len, exdr_string);
647    Tcl_ResetResult(interp);
648    return TCL_OK;
649}
650
651
652/*---------------------------------------------------------------------------
653 * Create the Tcl commands
654 *---------------------------------------------------------------------------*/
655
656int
657Tkeclipse_Init(Tcl_Interp *interp)
658{
659    Tcl_CreateObjCommand(interp, "ec_init_", EcInit,
660                       (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
661    Tcl_CreateObjCommand(interp, "ec_cleanup", EcCleanup,
662                       (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
663    Tcl_CreateObjCommand(interp, "ec_set_option", EcSetOption,
664                       (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
665    Tcl_CreateObjCommand(interp, "ec_post_goal", EcPostGoal,
666                       (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
667    Tcl_CreateObjCommand(interp, "ec_post_event", EcPostEvent,
668                       (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
669    Tcl_CreateObjCommand(interp, "ec_resume_", EcResume,
670                       (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
671    Tcl_CreateObjCommand(interp, "ec_running", EcRunning,
672                       (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
673    Tcl_CreateObjCommand(interp, "ec_resume_status", EcResumeStatus,
674                       (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
675    Tcl_CreateObjCommand(interp, "ec_handle_events_", EcHandleEvents,
676                       (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
677    Tcl_CreateObjCommand(interp, "ec_queue_write", EcQueueWrite,
678                       (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
679    Tcl_CreateObjCommand(interp, "ec_queue_read", EcQueueRead,
680                       (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
681    Tcl_CreateObjCommand(interp, "ec_stream_nr", EcStreamNr,
682                       (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
683
684    Tcl_CreateObjCommand(interp, "ec_queue_open_", EcQueueOpen,
685                       (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
686
687    return TCL_OK;
688}
689
690