#ifdef TESTING
#include <string.h>
static Obj logList = 0;
static void reset(void) {decr(logList); logList = 0;}
static Obj log(Obj message) {
if (!logList) logList = incr(Tcl_NewStringObj("LOG",-1));
Tcl_AppendToObj(logList,"\n",1);
Tcl_AppendObjToObj(logList,message);
return message;
}
static Obj show(void) {
if (!logList) logList = incr(Tcl_NewStringObj("LOG",-1));
return logList;
}
typedef struct {Obj script; int type; Tcl_TimerToken token; Tcl_Channel channel;} Callback;
static int qhandlercallback(ClientData clientData,Intr intr,int N,Tcl_Obj *const P[]) {
Callback *callback = clientData;
if (callback->type==2 || callback->type==3) {
char buffer[4096];
while (cread(callback->channel,buffer,sizeof buffer)>0) ;
}
decr(log(oprintf("callback script=SC<%x> type=%d intr=IN<%x> %{y-}s",
callback->script,callback->type,intr,incr(Tcl_NewListObj(N,P)))));
Tcl_SetVar(intr,"CALLBACK","1",TCL_GLOBAL_ONLY);
int rc = Tcl_EvalObjEx(intr,callback->script,0);
if (callback->type==3 && Tcl_Eof(callback->channel)) {
Tcl_UnregisterChannel(intr,callback->channel); return TCL_OK;
}
return rc;
}
static void qhandlerdelete(Intr intr,ClientData clientData) {
Callback *callback = clientData;
int deleted = Tcl_InterpDeleted(intr);
decr(log(oprintf("delete script=SC<%x> type=%d intr=IN<%x> del=%d can=%d",
callback->script,callback->type,intr,deleted,wyrm_handlerCancelled(intr))));
if (!deleted) {
Tcl_SetVar(intr,"CALLBACK","0",TCL_GLOBAL_ONLY);
if (Tcl_EvalObjEx(intr,callback->script,0)!=TCL_OK) decr(log(oprintf("script failed")));
}
switch (callback->type) {
case 1:
if (wyrm_handlerCancelled(intr)) {
Tcl_DeleteTimerHandler(callback->token);
}
break;
case 2:
Tcl_DeleteCloseHandler(callback->channel,wyrm_handlerCallbackProc,wyrm_handlerSelf(intr));
break;
case 3:
Tcl_DeleteChannelHandler(callback->channel,wyrm_handlerChannelProc,wyrm_handlerSelf(intr));
break;
}
decr(callback->script); dispose(callback);
}
static int qhandlercommand(ClientData clientData,Intr intr,int N,Tcl_Obj *const P[]) {
int index;
static chars subcommand[] = {
"newhandler","self",
"commandinterpretter",
"freehandler","freeself","cancelled",
"argument",
"log","reset","show",
"timer","closer","channel",
"create","eval","delete",
0
};
enum {
o_newhandler,o_self,
o_commandinterpretter,
o_freehandler,o_freeself,o_cancelled,
o_argument,
o_log,o_reset,o_show,
o_timer,o_closer,o_channel,
o_create,o_eval,o_delete
};
if (Tcl_GetIndexFromObj(intr,P[1],(CONST char**)subcommand,"subcommand",0,&index)!=TCL_OK) return TCL_ERROR;
switch (index) {
case o_newhandler: {
/* qhandler newhandler script ... -> CB<x> SC<x> IN<x> */
Callback *callback = heap(Callback);
callback->script = incr(P[2]); callback->type = 0;
ClientData handler = wyrm_handler(intr,qhandlercallback,callback,qhandlerdelete,N-3,P+3);
rprintf(intr,"CB<%x> SC<%x> IN<%x>",handler,P[2],intr);
return TCL_OK;
}
case o_self: {
/* qhandler self IN<x> -> CB<x> */
Intr x = (Intr)(strtol(strchr(Tcl_GetString(P[2]),'<')+1,0,16));
rprintf(intr,"CB<%x>",wyrm_handlerSelf(x));
return TCL_OK;
}
case o_commandinterpretter: {
/* qhandler commandinterpretter -> IN<x> */
rprintf(intr,"IN<%x>",intr);
return TCL_OK;
}
case o_freehandler: {
/* qhandler freehandler CB<x> -> */
ClientData handler = (ClientData)(strtol(strchr(Tcl_GetString(P[2]),'<')+1,0,16));
wyrm_handlerFree(handler);
return TCL_OK;
}
case o_freeself: {
/* qhandler freeself IN<x> -> */
Intr x = (Intr)(strtol(strchr(Tcl_GetString(P[2]),'<')+1,0,16));
wyrm_handlerFreeSelf(x);
return TCL_OK;
}
case o_cancelled: {
/* qhandler cancelled IN<x> -> */
Intr x = (Intr)(strtol(strchr(Tcl_GetString(P[2]),'<')+1,0,16));
Tcl_SetObjResult(intr,Tcl_NewBooleanObj(wyrm_handlerCancelled(x)));
return TCL_OK;
}
case o_argument: {
/* qhandler argument CB<x> ... -> */
ClientData handler = (ClientData)(strtol(strchr(Tcl_GetString(P[2]),'<')+1,0,16));
for (N-=3,P+=3; N>0; N--,P++) wyrm_handlerArg(handler,*P);
return TCL_OK;
}
case o_log: {
/* qhandler log message -> */
log(P[2]);
return TCL_OK;
}
case o_reset: {
/* qhandler reset -> */
reset();
return TCL_OK;
}
case o_show: {
/* qhandler show -> messages */
Tcl_SetObjResult(intr,show());
return TCL_OK;
}
case o_timer: {
/* qhandler timer CB<x> msecs -> */
ClientData handler = (ClientData)(strtol(strchr(Tcl_GetString(P[2]),'<')+1,0,16));
Handler *h = handler;
Callback *c = h->actualClientData;
long msecs; Tcl_GetLongFromObj(0,P[3],&msecs);
c->type = 1; c->token = Tcl_CreateTimerHandler(msecs,wyrm_handlerCallbackProc,handler);
return TCL_OK;
}
case o_closer: {
/* qhandler closer CB<x> channel -> */
ClientData handler = (ClientData)(strtol(strchr(Tcl_GetString(P[2]),'<')+1,0,16));
Handler *h = handler;
Callback *c = h->actualClientData;
int mood; Tcl_Channel channel = Tcl_GetChannel(intr,Tcl_GetString(P[3]),&mood);
c->type = 2; c->channel = channel;
Tcl_CreateCloseHandler(channel,wyrm_handlerCallbackProc,handler);
return TCL_OK;
}
case o_channel: {
/* qhandler channel CB<x> channel -> */
ClientData handler = (ClientData)(strtol(strchr(Tcl_GetString(P[2]),'<')+1,0,16));
Handler *h = handler;
Callback *c = h->actualClientData;
int mood; Tcl_Channel channel = Tcl_GetChannel(intr,Tcl_GetString(P[3]),&mood);
c->type = 3; c->channel = channel;
Tcl_CreateChannelHandler(channel,mood|TCL_EXCEPTION,wyrm_handlerChannelProc,handler);
return TCL_OK;
}
case o_create: {
char initialisation [] =
"source $tcl_library/init.tcl\n"
"package require msgcat\n"
"catch {\n"
"package require wyrmwif\n"
"package require wyrmhandler\n"
"namespace import wyrm::*\n"
"}\n"
;
Intr alt = Tcl_CreateInterp();
#ifdef TCL_MEM_DEBUG
Tcl_InitMemory(alt);
#endif
if (Tcl_Init(alt) == TCL_ERROR) {
fprintf(stderr,"interpretter Tcl_Init failed: %s\n",
Tcl_GetStringResult(alt));
}
Tcl_SetVar(alt,"tcl_rcFileName","~/.tclshrc",TCL_GLOBAL_ONLY);
Tcl_SourceRCFile(alt);
if (Tcl_Eval(alt,initialisation)!=TCL_OK) {
fprintf(stderr,"interpretter initialisation failed: %s\n%s",
Tcl_GetStringResult(alt),initialisation);
}
rprintf(intr,"IN<%x>",alt);
} return TCL_OK;
case o_eval: {
Intr alt = (Intr)(strtol(strchr(Tcl_GetString(P[2]),'<')+1,0,16));
int rc = Tcl_EvalObjEx(alt,P[3],0);
Tcl_SetObjResult(intr,Tcl_GetObjResult(alt));
return rc;
}
case o_delete: {
Intr alt = (Intr)(strtol(strchr(Tcl_GetString(P[2]),'<')+1,0,16));
Tcl_DeleteInterp(alt);
Tcl_ResetResult(intr);
return TCL_OK;
}
}
Tcl_Panic("you can't get here from there");
}
#endif
int Wyrmhandler_Init(Intr intr) {
Tcl_PkgRequire(intr,"wyrmwif","1",0);
Tcl_PkgProvide(intr,"wyrmhandler",VERSION);
#ifdef TESTING
Tcl_CreateObjCommand(intr,"::wyrm::qhandler",qhandlercommand,0,0);
return Tcl_VarEval(intr,"namespace eval ::wyrm {namespace export qhandler}",0);
#else
return TCL_OK;
#endif
}
int Wyrmhandler_SafeInit(Intr intr) {
return rprintf(intr,"This package only provides a C API; loading it has no benefit.",TCL_ERROR);
}