- First implementation of Hdbqueue
- First implementation of new object model for SICS
This commit is contained in:
412
hdbqueue.c
Normal file
412
hdbqueue.c
Normal file
@@ -0,0 +1,412 @@
|
||||
/**
|
||||
* This is the new Hipadaba based queuing system in support of the MountainGum
|
||||
* user interface.
|
||||
*
|
||||
* copyright: see file COPYRIGHT
|
||||
*
|
||||
* Mark Koennecke, July 2007
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <sics.h>
|
||||
#include "sicsobj.h"
|
||||
#include "hdbqueue.h"
|
||||
#include "sicshipadaba.h"
|
||||
#include "dynstring.h"
|
||||
#include "exeman.h"
|
||||
#include "macro.h"
|
||||
/*--------------------------------------------------------------------------*/
|
||||
typedef struct {
|
||||
int iStop;
|
||||
SConnection *pCon;
|
||||
}HdbQueue, *pHdbQueue;
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static pHdbCallback CopyCallbackChain(pHdbCallback source){
|
||||
pHdbCallback current = NULL;
|
||||
pHdbCallback result = NULL;
|
||||
pHdbCallback head = NULL;
|
||||
pHdbCallback tail = NULL;
|
||||
|
||||
current = source;
|
||||
while(current != NULL){
|
||||
result = MakeHipadabaCallback(current->userCallback,
|
||||
current->userData,
|
||||
NULL,
|
||||
current->id,
|
||||
current->internalID);
|
||||
if(head == NULL){
|
||||
head = result;
|
||||
tail = result;
|
||||
} else {
|
||||
tail->next = result;
|
||||
result->previous = tail;
|
||||
tail = result;
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
return head;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static pHdb MakeNewEntry(char *name, pHdbCallback update){
|
||||
pHdb entry = NULL, child = NULL;
|
||||
hdbValue v;
|
||||
|
||||
v = MakeHdbText("Undefined");
|
||||
entry = MakeHipadabaNode(name,HIPNONE, 1);
|
||||
entry->updateCallbacks = CopyCallbackChain(update);
|
||||
child = MakeSICSHdbPar("description",usUser,v);
|
||||
child->updateCallbacks = CopyCallbackChain(update);
|
||||
AddHipadabaChild(entry,child,NULL);
|
||||
child = MakeSICSHdbPar("commands",usUser,v);
|
||||
child->updateCallbacks = CopyCallbackChain(update);
|
||||
AddHipadabaChild(entry,child,NULL);
|
||||
child = MakeSICSHdbPar("log",usUser,v);
|
||||
child->updateCallbacks = CopyCallbackChain(update);
|
||||
AddHipadabaChild(entry,child,NULL);
|
||||
|
||||
return entry;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int EnqueFunc(pSICSOBJ self, SConnection *pCon, pHdb par[], int nPar){
|
||||
pHdb entry = NULL;
|
||||
pHdb work = NULL;
|
||||
char name[80];
|
||||
hdbValue v;
|
||||
|
||||
if(nPar < 1){
|
||||
SCWrite(pCon,"ERROR: internal: not enough parameters to EnqueFunc",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* new entry
|
||||
*/
|
||||
memset(&v,0,sizeof(hdbValue));
|
||||
work = GetHipadabaNode(self->objectNode,"control/maxEntry");
|
||||
assert(work != NULL);
|
||||
snprintf(name,80,"%3.3d", work->value.v.intValue);
|
||||
entry = MakeNewEntry(name, work->updateCallbacks);
|
||||
if(entry == NULL){
|
||||
SCWrite(pCon,"ERROR: out of memory in EnqueFunc",eError);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Update maxEntry
|
||||
*/
|
||||
cloneHdbValue(&work->value,&v);
|
||||
v.v.intValue++;
|
||||
UpdateHipadabaPar(work,v,pCon);
|
||||
|
||||
work = GetHipadabaNode(self->objectNode,"queue");
|
||||
assert(work != NULL);
|
||||
AddHipadabaChild(work, entry, pCon);
|
||||
|
||||
/*
|
||||
* save description
|
||||
*/
|
||||
work = GetHipadabaNode(entry,"description");
|
||||
assert(work != NULL);
|
||||
UpdateHipadabaPar(work,par[0]->value,pCon);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int AddCmdData(pSICSOBJ self, SConnection *pCon, pHdb par[], int nPar){
|
||||
pHdb work = NULL;
|
||||
pHdb commandNode = NULL;
|
||||
char name[80];
|
||||
pDynString txt = NULL;
|
||||
|
||||
if(nPar < 1){
|
||||
SCWrite(pCon,"ERROR: internal: not enough parameters to AddCmdData",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
work = GetHipadabaNode(self->objectNode,"control/maxEntry");
|
||||
assert(work != NULL);
|
||||
snprintf(name,80,"queue/%3.3d/commands", work->value.v.intValue-1);
|
||||
commandNode = GetHipadabaNode(self->objectNode,name);
|
||||
if(commandNode == NULL){
|
||||
SCWrite(pCon,"ERROR: Internal error in AddCommand",eError);
|
||||
return 0;
|
||||
}
|
||||
txt = CreateDynString(80,80);
|
||||
if(strstr(commandNode->value.v.text,"Undefined") == NULL){
|
||||
DynStringCopy(txt,commandNode->value.v.text);
|
||||
}
|
||||
DynStringConcat(txt,par[0]->value.v.text);
|
||||
DynStringConcat(txt,"\n");
|
||||
free(commandNode->value.v.text);
|
||||
commandNode->value.v.text = strdup(GetCharArray(txt));
|
||||
NotifyHipadabaPar(commandNode,pCon);
|
||||
DeleteDynString(txt);
|
||||
return 1;
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static void sequentialNames(pHdb obj,SConnection *pCon){
|
||||
pHdb work = NULL;
|
||||
pHdb current = NULL;
|
||||
int count = 0;
|
||||
char name[80];
|
||||
|
||||
work = GetHipadabaNode(obj,"queue");
|
||||
assert(work != NULL);
|
||||
current = work->child;
|
||||
while(current != NULL){
|
||||
snprintf(name,80,"%3.3d",count);
|
||||
if(current != NULL && current->name != NULL){
|
||||
free(current->name);
|
||||
}
|
||||
current->name = strdup(name);
|
||||
count++;
|
||||
current = current->next;
|
||||
}
|
||||
InvokeCallbackChain(work->treeChangeCallbacks,work,pCon,work->value);
|
||||
|
||||
work = GetHipadabaNode(obj,"control/maxEntry");
|
||||
assert(work != NULL);
|
||||
work->value.v.intValue = count;
|
||||
NotifyHipadabaPar(work,pCon);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int Dequeue(pSICSOBJ self, SConnection *pCon, pHdb par[], int nPar){
|
||||
pHdb work = NULL;
|
||||
char name[80];
|
||||
|
||||
if(nPar < 1){
|
||||
SCWrite(pCon,"ERROR: internal: not enough parameters to Dequeue",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(name,80,"queue/%3.3d", par[0]->value.v.intValue);
|
||||
work = GetHipadabaNode(self->objectNode,name);
|
||||
if(work != NULL){
|
||||
DeleteHipadabaNode(work,pCon);
|
||||
sequentialNames(self->objectNode, pCon);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int Clean(pSICSOBJ self, SConnection *pCon, pHdb par[], int nPar){
|
||||
int i;
|
||||
pHdb current = NULL, queue = NULL;
|
||||
pHdb currentEntry = NULL, tmp;
|
||||
|
||||
currentEntry = GetHipadabaNode(self->objectNode,"control/currentEntry");
|
||||
queue = GetHipadabaNode(self->objectNode,"queue");
|
||||
current = queue->child;
|
||||
for(i = 0; i < currentEntry->value.v.intValue; i++){
|
||||
if(current != NULL){
|
||||
tmp = current->next;
|
||||
DeleteNodeData(current);
|
||||
current = tmp;
|
||||
}
|
||||
}
|
||||
queue->child = tmp;
|
||||
currentEntry->value.v.intValue = 0;
|
||||
sequentialNames(self->objectNode, pCon);
|
||||
NotifyHipadabaPar(currentEntry,pCon);
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int QueueTask(void *pData){
|
||||
pSICSOBJ self = (pSICSOBJ)pData;
|
||||
int status, pos;
|
||||
pHdb work = NULL;
|
||||
pHdb exeNode = NULL;
|
||||
pHdb max = NULL;
|
||||
char name[80];
|
||||
pHdbQueue priv = (pHdbQueue)self->pPrivate;
|
||||
|
||||
if(priv->iStop == 1){
|
||||
return 0;
|
||||
}
|
||||
|
||||
work = GetHipadabaNode(self->objectNode,"control/currentEntry");
|
||||
max = GetHipadabaNode(self->objectNode,"control/maxEntry");
|
||||
assert(work != NULL && max != NULL);
|
||||
pos = work->value.v.intValue;
|
||||
snprintf(name,80,"queue/%3.3d", pos);
|
||||
|
||||
exeNode = GetHipadabaNode(self->objectNode,name);
|
||||
if(exeNode != NULL){
|
||||
MacroPush(priv->pCon);
|
||||
exeHdbNode(exeNode, priv->pCon);
|
||||
MacroPop();
|
||||
}
|
||||
if(priv->iStop == 1 || SCGetInterrupt(priv->pCon) != eContinue){
|
||||
return 0;
|
||||
}
|
||||
|
||||
pos++;
|
||||
work->value.v.intValue = pos;
|
||||
NotifyHipadabaPar(work,priv->pCon);
|
||||
if(pos >= max->value.v.intValue){
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int Start(pSICSOBJ self, SConnection *pCon, pHdb par[], int nPar){
|
||||
pHdbQueue priv = (pHdbQueue)self->pPrivate;
|
||||
|
||||
priv->iStop = 0;
|
||||
priv->pCon = pCon;
|
||||
|
||||
TaskRegister(pServ->pTasker,
|
||||
QueueTask,
|
||||
NULL,
|
||||
NULL,
|
||||
self,
|
||||
10);
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static int Stop(pSICSOBJ self, SConnection *pCon, pHdb par[], int nPar){
|
||||
pHdbQueue priv = (pHdbQueue)self->pPrivate;
|
||||
|
||||
priv->iStop = 1;
|
||||
return 1;
|
||||
}
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int Move(pSICSOBJ self, SConnection *pCon, pHdb par[], int nPar){
|
||||
pHdb moveNode = NULL;
|
||||
pHdb insertNode = NULL;
|
||||
pHdb prevNode = NULL, queueNode = NULL;
|
||||
pHdb tmp;
|
||||
char name[80];
|
||||
|
||||
if(nPar < 2){
|
||||
SCWrite(pCon,"ERROR: internal: not enough parameters to Move",eError);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(par[1]->value.v.intValue == par[0]->value.v.intValue + 1){
|
||||
/*
|
||||
* already in right sequence, nothing to do
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
snprintf(name,80,"queue/%3.3d", par[1]->value.v.intValue);
|
||||
moveNode = GetHipadabaNode(self->objectNode,name);
|
||||
|
||||
snprintf(name,80,"queue/%3.3d", par[0]->value.v.intValue);
|
||||
insertNode = GetHipadabaNode(self->objectNode,name);
|
||||
if(moveNode == NULL || insertNode == NULL){
|
||||
SCWrite(pCon,"ERROR: move not possible, participating nodes not found",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
queueNode = GetHipadabaNode(self->objectNode,"queue");
|
||||
|
||||
if(moveNode == queueNode->child){
|
||||
queueNode->child = queueNode->child->next;
|
||||
moveNode->next = insertNode->next;
|
||||
insertNode->next = moveNode;
|
||||
} else {
|
||||
prevNode = queueNode->child;
|
||||
while(prevNode != NULL && prevNode->next != moveNode){
|
||||
prevNode = prevNode->next;
|
||||
}
|
||||
if(insertNode == queueNode->child ){
|
||||
/*
|
||||
* insert at top
|
||||
*/
|
||||
tmp = queueNode->child;
|
||||
queueNode->child = moveNode;
|
||||
prevNode->next = moveNode->next;
|
||||
moveNode->next = tmp;
|
||||
} else {
|
||||
tmp = insertNode->next;
|
||||
insertNode->next = moveNode;
|
||||
prevNode->next = moveNode->next;
|
||||
moveNode->next = tmp;
|
||||
}
|
||||
}
|
||||
sequentialNames(self->objectNode, pCon);
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void Configure(pSICSOBJ self){
|
||||
pHdb n = NULL, par = NULL;
|
||||
hdbValue intValue, textValue, funcValue;
|
||||
pHdb obj = self->objectNode;
|
||||
|
||||
intValue = MakeHdbInt(0);
|
||||
textValue = MakeHdbText("Undefined");
|
||||
|
||||
n = MakeHipadabaNode("control",HIPNONE,1);
|
||||
AddHipadabaChild(obj,n,NULL);
|
||||
AddSICSHdbPar(n,"maxEntry",usInternal,intValue);
|
||||
AddSICSHdbPar(n,"currentEntry",usInternal,intValue);
|
||||
|
||||
|
||||
n = MakeHipadabaNode("queue",HIPNONE,1);
|
||||
AddHipadabaChild(obj,n, NULL);
|
||||
|
||||
funcValue = makeHdbData(HIPFUNC,1,EnqueFunc);
|
||||
n = MakeSICSHdbPar("enqueue",usUser, funcValue);
|
||||
AddSICSHdbPar(n,"description",usUser,textValue);
|
||||
AddHipadabaChild(obj,n,NULL);
|
||||
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
|
||||
|
||||
funcValue = makeHdbData(HIPFUNC,1,AddCmdData);
|
||||
n = MakeSICSHdbPar("addcommand",usUser, funcValue);
|
||||
AddSICSHdbPar(n,"command",usUser,textValue);
|
||||
AddHipadabaChild(obj,n,NULL);
|
||||
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
|
||||
|
||||
|
||||
funcValue = makeHdbData(HIPFUNC,1,Dequeue);
|
||||
n = MakeSICSHdbPar("dequeue",usUser,funcValue);
|
||||
AddHipadabaChild(obj,n,NULL);
|
||||
AddSICSHdbPar(n,"index",usUser,intValue);
|
||||
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
|
||||
|
||||
|
||||
funcValue = makeHdbData(HIPFUNC,1,Clean);
|
||||
n = MakeSICSHdbPar("clean",usUser, funcValue);
|
||||
AddHipadabaChild(obj,n,NULL);
|
||||
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
|
||||
|
||||
funcValue = makeHdbData(HIPFUNC,1,Start);
|
||||
n = MakeSICSHdbPar("start",usUser, funcValue);
|
||||
AddHipadabaChild(obj,n,NULL);
|
||||
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
|
||||
|
||||
funcValue = makeHdbData(HIPFUNC,1,Stop);
|
||||
n = MakeSICSHdbPar("stop",usUser, funcValue);
|
||||
AddHipadabaChild(obj,n,NULL);
|
||||
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
|
||||
|
||||
funcValue = makeHdbData(HIPFUNC,1,Move);
|
||||
n = MakeSICSHdbPar("move",usUser,funcValue);
|
||||
AddHipadabaChild(obj,n,NULL);
|
||||
AddSICSHdbPar(n,"moveindex",usUser,intValue);
|
||||
AddSICSHdbPar(n,"insertindex",usUser,intValue);
|
||||
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
|
||||
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
int MakeHDBQueue(SConnection *pCon, SicsInterp *pSics, void *pData,
|
||||
int argc, char *argv[]){
|
||||
pSICSOBJ self = NULL;
|
||||
pHdbQueue priv = NULL;
|
||||
|
||||
priv = (pHdbQueue)malloc(sizeof(HdbQueue));
|
||||
self = SetupSICSOBJ(pCon,pSics, pData,argc, argv);
|
||||
if(self == NULL || priv == NULL){
|
||||
return 0;
|
||||
}
|
||||
Configure(self);
|
||||
memset(priv,0,sizeof(HdbQueue));
|
||||
self->pPrivate = priv;
|
||||
self->KillPrivate = free;
|
||||
return 1;
|
||||
}
|
||||
Reference in New Issue
Block a user