- added status function
- added hostport function - added update script - added reconnenct script - added "sct parent" command
This commit is contained in:
316
scriptcontext.c
316
scriptcontext.c
@ -48,6 +48,12 @@ typedef struct SctData {
|
|||||||
Hdb *node;
|
Hdb *node;
|
||||||
} SctData;
|
} SctData;
|
||||||
|
|
||||||
|
/* data for updatescript */
|
||||||
|
typedef struct SctUpdatescript {
|
||||||
|
char *name;
|
||||||
|
SctController *controller;
|
||||||
|
} SctUpdatescript;
|
||||||
|
|
||||||
static ScriptContext *sct = NULL;
|
static ScriptContext *sct = NULL;
|
||||||
static SctData *queueData = NULL;
|
static SctData *queueData = NULL;
|
||||||
|
|
||||||
@ -55,6 +61,8 @@ static struct {
|
|||||||
char *name;
|
char *name;
|
||||||
} actionCallback;
|
} actionCallback;
|
||||||
|
|
||||||
|
static struct SctUpdatescript updatescriptCallback;
|
||||||
|
|
||||||
void PushContext(Hdb * node, SctController * controller)
|
void PushContext(Hdb * node, SctController * controller)
|
||||||
{
|
{
|
||||||
ContextItem *new;
|
ContextItem *new;
|
||||||
@ -177,7 +185,7 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get path
|
* get path (pure sct command)
|
||||||
*/
|
*/
|
||||||
if (argc <= 1) {
|
if (argc <= 1) {
|
||||||
GetHdbPath(node, value, sizeof value);
|
GetHdbPath(node, value, sizeof value);
|
||||||
@ -236,19 +244,6 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* send command
|
|
||||||
*/
|
|
||||||
if (strcmp(argv[1], "send") == 0 && argc > 2) {
|
|
||||||
if (sct->sendNode != node) {
|
|
||||||
SCPrintf(con, eError, "ERROR: %s may be called only in action scripts",
|
|
||||||
argv[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
sct->sendCalled = 1;
|
|
||||||
/* continue with property handling */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* with command (execute a script in the context of an other node)
|
* with command (execute a script in the context of an other node)
|
||||||
*/
|
*/
|
||||||
@ -273,6 +268,37 @@ int SctCommand(SConnection * con, SicsInterp * sics, void *object,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* parent command (return path of parent node)
|
||||||
|
*/
|
||||||
|
if (strcmp(argv[1], "parent") == 0) {
|
||||||
|
if (argc > 3) {
|
||||||
|
SCPrintf(con, eError, "ERROR: syntax must be: %s %s [path]",
|
||||||
|
argv[0], argv[1]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (argc == 3) {
|
||||||
|
node = FindHdbNode(NULL, argv[2], con);
|
||||||
|
}
|
||||||
|
GetHdbPath(node->mama, value, sizeof value);
|
||||||
|
/* returns an empty string on error */
|
||||||
|
SCWrite(con, value, eValue);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* send command
|
||||||
|
*/
|
||||||
|
if (strcmp(argv[1], "send") == 0 && argc > 2) {
|
||||||
|
if (sct->sendNode != node) {
|
||||||
|
SCPrintf(con, eError, "ERROR: %s may be called only in action scripts",
|
||||||
|
argv[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
sct->sendCalled = 1;
|
||||||
|
/* continue with property handling */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* property handling
|
* property handling
|
||||||
*/
|
*/
|
||||||
@ -377,7 +403,7 @@ static char *SctActionHandler(void *actionData, char *lastReply,
|
|||||||
SConnection *con;
|
SConnection *con;
|
||||||
char eprop[80];
|
char eprop[80];
|
||||||
char msg[1024];
|
char msg[1024];
|
||||||
char path[1024];
|
char path[MAX_HDB_PATH];
|
||||||
char origScript[80];
|
char origScript[80];
|
||||||
char *blank;
|
char *blank;
|
||||||
char *emsg;
|
char *emsg;
|
||||||
@ -387,6 +413,7 @@ static char *SctActionHandler(void *actionData, char *lastReply,
|
|||||||
char timeKey[50], timeVal[50];
|
char timeKey[50], timeVal[50];
|
||||||
int iMacro;
|
int iMacro;
|
||||||
|
|
||||||
|
assert(data->name);
|
||||||
if (queueData != NULL && queueData->conCtx != NULL) {
|
if (queueData != NULL && queueData->conCtx != NULL) {
|
||||||
con = queueData->conCtx;
|
con = queueData->conCtx;
|
||||||
} else {
|
} else {
|
||||||
@ -637,7 +664,6 @@ static hdbCallbackReturn SctMainCallback(Hdb * node, void *userData,
|
|||||||
hdbDataMessage *mm;
|
hdbDataMessage *mm;
|
||||||
hdbPtrMessage *pm;
|
hdbPtrMessage *pm;
|
||||||
hdbMessage *km;
|
hdbMessage *km;
|
||||||
ContextItem *s;
|
|
||||||
SConnection *con;
|
SConnection *con;
|
||||||
char *geterror;
|
char *geterror;
|
||||||
char error[256];
|
char error[256];
|
||||||
@ -699,7 +725,6 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData,
|
|||||||
hdbDataSearch *dsm;
|
hdbDataSearch *dsm;
|
||||||
hdbDataMessage *mm;
|
hdbDataMessage *mm;
|
||||||
hdbPtrMessage *pm;
|
hdbPtrMessage *pm;
|
||||||
hdbMessage *km;
|
|
||||||
SctData *data = userData;
|
SctData *data = userData;
|
||||||
Hdb *target;
|
Hdb *target;
|
||||||
char *script;
|
char *script;
|
||||||
@ -746,8 +771,10 @@ static hdbCallbackReturn SctActionCallback(Hdb * node, void *userData,
|
|||||||
if (script != NULL) {
|
if (script != NULL) {
|
||||||
if (SctCallInContext(con, script, node, data->controller, &error) ==
|
if (SctCallInContext(con, script, node, data->controller, &error) ==
|
||||||
0) {
|
0) {
|
||||||
SCPrintf(con, eError, "ERROR: in {%s}: %s", script, error);
|
/* SCPrintf(con, eError, "ERROR: in {%s}: %s", script, error); */
|
||||||
|
SCPrintf(con, eError, "ERROR: %s", error); /* nicer for the user */
|
||||||
SetHdbProperty(node, "target", NULL);
|
SetHdbProperty(node, "target", NULL);
|
||||||
|
SetHdbProperty(node, "requested", NULL);
|
||||||
return hdbAbort;
|
return hdbAbort;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -858,8 +885,10 @@ static void SctKillData(void *d)
|
|||||||
{
|
{
|
||||||
SctData *data = d;
|
SctData *data = d;
|
||||||
|
|
||||||
if (data->name)
|
if (data->name) {
|
||||||
free(data->name);
|
free(data->name);
|
||||||
|
data->name = NULL;
|
||||||
|
}
|
||||||
if (data->conCtx)
|
if (data->conCtx)
|
||||||
SCDeleteConnection(data->conCtx);
|
SCDeleteConnection(data->conCtx);
|
||||||
free(data);
|
free(data);
|
||||||
@ -1135,6 +1164,180 @@ static int SctQueueCmd(pSICSOBJ ccmd, SConnection * con,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SctKillUpdatescript(void *d)
|
||||||
|
{
|
||||||
|
SctUpdatescript *us = d;
|
||||||
|
|
||||||
|
if (us->name) {
|
||||||
|
free(us->name);
|
||||||
|
}
|
||||||
|
free(us);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the callback for update scripts
|
||||||
|
*/
|
||||||
|
static hdbCallbackReturn SctUpdatescriptCallback(Hdb * node,
|
||||||
|
void *userData,
|
||||||
|
hdbMessage * msg)
|
||||||
|
{
|
||||||
|
SctUpdatescript *us = userData;
|
||||||
|
hdbDataSearch *dsm;
|
||||||
|
hdbDataMessage *mm;
|
||||||
|
hdbPtrMessage *pm;
|
||||||
|
SConnection *con;
|
||||||
|
char *result;
|
||||||
|
char *script;
|
||||||
|
char path[MAX_HDB_PATH];
|
||||||
|
pDynString text;
|
||||||
|
char *arg;
|
||||||
|
|
||||||
|
pm = GetKillPtrMessage(msg);
|
||||||
|
if (pm != NULL) {
|
||||||
|
if (us->controller == pm->pPtr) {
|
||||||
|
return hdbKill;
|
||||||
|
}
|
||||||
|
if (pm->pPtr == &updatescriptCallback
|
||||||
|
&& strcmp(us->name, updatescriptCallback.name) == 0
|
||||||
|
&& us->controller == updatescriptCallback.controller) {
|
||||||
|
return hdbKill;
|
||||||
|
}
|
||||||
|
return hdbContinue;
|
||||||
|
}
|
||||||
|
dsm = GetHdbDataSearchMessage(msg);
|
||||||
|
if (dsm != NULL) {
|
||||||
|
if (dsm->testPtr == &updatescriptCallback) {
|
||||||
|
if (strcasecmp(us->name, updatescriptCallback.name) == 0 &&
|
||||||
|
us->controller == updatescriptCallback.controller) {
|
||||||
|
dsm->result = us;
|
||||||
|
}
|
||||||
|
return hdbAbort;
|
||||||
|
}
|
||||||
|
return hdbContinue;
|
||||||
|
}
|
||||||
|
mm = GetHdbUpdateMessage(msg);
|
||||||
|
if (mm != NULL) {
|
||||||
|
con = mm->callData;
|
||||||
|
|
||||||
|
script = GetProp(node, us->controller->node, us->name);
|
||||||
|
if (script == NULL) script = us->name;
|
||||||
|
|
||||||
|
text = formatValue(*(mm->v), node);
|
||||||
|
arg = GetCharArray(text);
|
||||||
|
arg = Arg2Tcl(1, &arg, NULL, 0);
|
||||||
|
DynStringCopy(text, script);
|
||||||
|
DynStringConcat(text, " ");
|
||||||
|
DynStringConcat(text, arg);
|
||||||
|
free(arg);
|
||||||
|
script = GetCharArray(text);
|
||||||
|
|
||||||
|
if (!SctCallInContext(con, script, node, us->controller, &result)) {
|
||||||
|
|
||||||
|
GetHdbPath(node, path, sizeof path);
|
||||||
|
SCPrintf(con, eError, "ERROR: in updatescript {%s} node %s: %s",
|
||||||
|
script, path, result);
|
||||||
|
}
|
||||||
|
DeleteDynString(text);
|
||||||
|
return hdbContinue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hdbContinue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SctUpdatescriptNode(SctController * controller, Hdb * node, char *action)
|
||||||
|
{
|
||||||
|
SctUpdatescript *us;
|
||||||
|
hdbCallback *cb;
|
||||||
|
|
||||||
|
updatescriptCallback.name = action;
|
||||||
|
updatescriptCallback.controller = controller;
|
||||||
|
us = FindHdbCallbackData(node, &updatescriptCallback);
|
||||||
|
if (us != NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
us = calloc(1, sizeof(*us));
|
||||||
|
us->name = strdup(action);
|
||||||
|
us->controller = controller;
|
||||||
|
cb = MakeHipadabaCallback(SctUpdatescriptCallback, us, SctKillUpdatescript);
|
||||||
|
assert(cb);
|
||||||
|
AppendHipadabaCallback(node, cb);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SctUpdatescriptKill(SctController * controller, Hdb * node, char *action)
|
||||||
|
{
|
||||||
|
updatescriptCallback.name = action;
|
||||||
|
updatescriptCallback.controller = controller;
|
||||||
|
RemoveSICSInternalCallbackFrom(node, &updatescriptCallback);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SctUpdatescriptCmd(pSICSOBJ ccmd, SConnection * con,
|
||||||
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||||
|
{
|
||||||
|
Hdb *node;
|
||||||
|
SctController *controller;
|
||||||
|
double interval;
|
||||||
|
char *path;
|
||||||
|
char *action;
|
||||||
|
SctData *data;
|
||||||
|
char *prioText;
|
||||||
|
|
||||||
|
if (nPar < 2) {
|
||||||
|
SCPrintf(con, eError,
|
||||||
|
"ERROR: should be: %s updatescript <node> <action>",
|
||||||
|
ccmd->objectNode->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
controller = ccmd->pPrivate;
|
||||||
|
path = ParText(cmdNode, "node", nPar, "");
|
||||||
|
node = FindHdbNode(NULL, path, con);
|
||||||
|
if (node == NULL) {
|
||||||
|
SCPrintf(con, eError, "ERROR: %s not found", path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
action = ParText(cmdNode, "action", nPar, "updatescript");
|
||||||
|
|
||||||
|
if (SctUpdatescriptNode(controller, node, action)) {
|
||||||
|
SCPrintf(con, eValue, "%s registered for update on %s", action, path);
|
||||||
|
} else {
|
||||||
|
SCPrintf(con, eValue, "%s already registered for update on %s", action, path);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SctKillUpdatescriptCmd(pSICSOBJ ccmd, SConnection * con,
|
||||||
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||||
|
{
|
||||||
|
Hdb *node;
|
||||||
|
SctController *controller;
|
||||||
|
double interval;
|
||||||
|
char *path;
|
||||||
|
char *action;
|
||||||
|
SctData *data;
|
||||||
|
char *prioText;
|
||||||
|
|
||||||
|
if (nPar < 2) {
|
||||||
|
SCPrintf(con, eError,
|
||||||
|
"ERROR: should be: %s killupdatescript <node> <action>",
|
||||||
|
ccmd->objectNode->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
controller = ccmd->pPrivate;
|
||||||
|
path = ParText(cmdNode, "node", nPar, "");
|
||||||
|
node = FindHdbNode(NULL, path, con);
|
||||||
|
if (node == NULL) {
|
||||||
|
SCPrintf(con, eError, "ERROR: %s not found", path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
action = ParText(cmdNode, "action", nPar, "updatescript");
|
||||||
|
|
||||||
|
SctUpdatescriptKill(controller, node, action);
|
||||||
|
SCPrintf(con, eValue, "kill %s updatescript on %s", action, path);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct SctTransact {
|
typedef struct SctTransact {
|
||||||
char *command;
|
char *command;
|
||||||
char *reply;
|
char *reply;
|
||||||
@ -1191,16 +1394,37 @@ static char *TransactionHandler(void *actionData, char *lastReply,
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
/* printf("Transact: %s got %s\n", st->command, lastReply); */
|
/* printf("Transact: %s got %s\n", st->command, lastReply); */
|
||||||
if(st->controller != NULL){
|
if (lastReply == NULL) {
|
||||||
|
lastReply = "";
|
||||||
|
}
|
||||||
|
if(st->controller != NULL){
|
||||||
traceIO(st->controller->node->name, "transreply:%s", lastReply);
|
traceIO(st->controller->node->name, "transreply:%s", lastReply);
|
||||||
} else {
|
} else {
|
||||||
traceIO("sctunknown", "transreply:%s", lastReply);
|
traceIO("sctunknown", "transreply:%s", lastReply);
|
||||||
}
|
}
|
||||||
st->reply = strdup(lastReply);
|
st->reply = strdup(lastReply);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *SendHandler(void *actionData, char *lastReply,
|
||||||
|
int commError)
|
||||||
|
{
|
||||||
|
pSctTransact st = (pSctTransact) actionData;
|
||||||
|
char *result = TransactionHandler(actionData, lastReply, commError);
|
||||||
|
|
||||||
|
if (st->sent == 2) {
|
||||||
|
SetHdbProperty(st->controller->node, "reply", lastReply);
|
||||||
|
if (st->controller->verbose) {
|
||||||
|
SCPrintf(st->con, eLog, "%6.3f reply : %s", secondsOfMinute(), lastReply);
|
||||||
|
}
|
||||||
|
if (st->controller->fd != NULL) {
|
||||||
|
fprintf(st->controller->fd, "%6.3f reply : %s\n", secondsOfMinute(), lastReply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static int SctTransactMatch(void *d1, void *d2)
|
static int SctTransactMatch(void *d1, void *d2)
|
||||||
{
|
{
|
||||||
return d1 == d2;
|
return d1 == d2;
|
||||||
@ -1280,8 +1504,9 @@ static int SctSendCmd(pSICSOBJ ccmd, SConnection * con,
|
|||||||
prio = WritePRIO;
|
prio = WritePRIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetHdbProperty(c->node, "reply", "");
|
||||||
DevQueue(c->devser, st, prio,
|
DevQueue(c->devser, st, prio,
|
||||||
TransactionHandler, SctTransactMatch, KillSctTransact, NULL);
|
SendHandler, SctTransactMatch, KillSctTransact, NULL);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1299,9 +1524,17 @@ static int SctReconnect(pSICSOBJ ccmd, SConnection * con,
|
|||||||
Hdb * cmdNode, Hdb * par[], int nPar)
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||||
{
|
{
|
||||||
SctController *c;
|
SctController *c;
|
||||||
|
char *reconnectScript, *result;
|
||||||
|
|
||||||
c = (SctController *) ccmd->pPrivate;
|
c = (SctController *) ccmd->pPrivate;
|
||||||
DevReconnect(c->devser, ParText(cmdNode, "hostport", nPar, ""));
|
DevReconnect(c->devser, ParText(cmdNode, "hostport", nPar, ""));
|
||||||
|
reconnectScript = GetProp(c->node, c->node, "reconnect_script");
|
||||||
|
if (reconnectScript && reconnectScript[0] != '\0') {
|
||||||
|
if (SctCallInContext(con, reconnectScript, c->node, c, &result) == 0) {
|
||||||
|
SCPrintf(con, eError, "ERROR: %s", result);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1342,6 +1575,30 @@ static int SctStatistics(pSICSOBJ ccmd, SConnection * con,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int SctHostport(pSICSOBJ ccmd, SConnection * con,
|
||||||
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||||
|
{
|
||||||
|
SctController *c;
|
||||||
|
char *result;
|
||||||
|
|
||||||
|
c = (SctController *) ccmd->pPrivate;
|
||||||
|
result = DevHostport(c->devser);
|
||||||
|
SCWrite(con, result, eValue);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SctStatus(pSICSOBJ ccmd, SConnection * con,
|
||||||
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||||
|
{
|
||||||
|
SctController *c;
|
||||||
|
char *result;
|
||||||
|
|
||||||
|
c = (SctController *) ccmd->pPrivate;
|
||||||
|
result = DevStatus(c->devser);
|
||||||
|
SCWrite(con, result, eValue);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int SctLog(pSICSOBJ ccmd, SConnection * con,
|
static int SctLog(pSICSOBJ ccmd, SConnection * con,
|
||||||
Hdb * cmdNode, Hdb * par[], int nPar)
|
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||||
{
|
{
|
||||||
@ -1517,6 +1774,15 @@ static int SctMakeController(SConnection * con, SicsInterp * sics,
|
|||||||
AddSICSHdbPar(cmd, "prio", usMugger, MakeHdbText("write"));
|
AddSICSHdbPar(cmd, "prio", usMugger, MakeHdbText("write"));
|
||||||
AddSICSHdbPar(cmd, "action", usMugger, MakeHdbText("write"));
|
AddSICSHdbPar(cmd, "action", usMugger, MakeHdbText("write"));
|
||||||
|
|
||||||
|
cmd = AddSICSHdbPar(controller->node,
|
||||||
|
"updatescript", usMugger, MakeSICSFunc(SctUpdatescriptCmd));
|
||||||
|
AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText(""));
|
||||||
|
AddSICSHdbPar(cmd, "action", usMugger, MakeHdbText("updatescript"));
|
||||||
|
|
||||||
|
cmd = AddSICSHdbPar(controller->node,
|
||||||
|
"killupdatescript", usMugger, MakeSICSFunc(SctKillUpdatescriptCmd));
|
||||||
|
AddSICSHdbPar(cmd, "node", usMugger, MakeHdbText(""));
|
||||||
|
AddSICSHdbPar(cmd, "action", usMugger, MakeHdbText("updatescript"));
|
||||||
|
|
||||||
cmd = AddSICSHdbPar(controller->node,
|
cmd = AddSICSHdbPar(controller->node,
|
||||||
"log", usMugger, MakeSICSFunc(SctLog));
|
"log", usMugger, MakeSICSFunc(SctLog));
|
||||||
@ -1546,6 +1812,12 @@ static int SctMakeController(SConnection * con, SicsInterp * sics,
|
|||||||
cmd = AddSICSHdbPar(controller->node,
|
cmd = AddSICSHdbPar(controller->node,
|
||||||
"statistics", usSpy, MakeSICSFunc(SctStatistics));
|
"statistics", usSpy, MakeSICSFunc(SctStatistics));
|
||||||
|
|
||||||
|
cmd = AddSICSHdbPar(controller->node,
|
||||||
|
"hostport", usSpy, MakeSICSFunc(SctHostport));
|
||||||
|
|
||||||
|
cmd = AddSICSHdbPar(controller->node,
|
||||||
|
"status", usSpy, MakeSICSFunc(SctStatus));
|
||||||
|
|
||||||
cb = MakeHipadabaCallback(SctDebugCallback, controller, NULL);
|
cb = MakeHipadabaCallback(SctDebugCallback, controller, NULL);
|
||||||
if (cb)
|
if (cb)
|
||||||
AppendHipadabaCallback(par, cb);
|
AppendHipadabaCallback(par, cb);
|
||||||
|
Reference in New Issue
Block a user