Files
sics/hdbqueue.c
zolliker b03ddddd8f - add MskeSICSFunc
- changed return value of AddSICSHdbPar et al.
2008-05-15 07:43:05 +00:00

498 lines
15 KiB
C

/**
* 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;
int isRunning;
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, Hdb commandNode,
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, Hdb comNode,
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->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 commandNode,
pHdb par[], int nPar){
pHdb work = NULL;
char name[80];
pHdbQueue priv = (pHdbQueue)self->pPrivate;
if(priv->isRunning == 1){
SCWrite(pCon,"ERROR: cannot dequeue while running",eError);
return 0;
}
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,Hdb commandNode,
pHdb par[], int nPar){
int i;
pHdb current = NULL, queue = NULL;
pHdb currentEntry = NULL, tmp = NULL;
pHdbQueue priv = (pHdbQueue)self->pPrivate;
if(priv->isRunning == 1){
SCWrite(pCon,"ERROR: cannot clean while running",eError);
return 0;
}
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 CleanAll(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
pHdb par[], int nPar){
int i;
pHdb current = NULL, queue = NULL;
pHdb currentEntry = NULL, tmp;
pHdbQueue priv = (pHdbQueue)self->pPrivate;
if(priv->isRunning == 1){
SCWrite(pCon,"ERROR: cannot clear queue while executing",eError);
return 0;
}
currentEntry = GetHipadabaNode(self->objectNode,"control/currentEntry");
queue = GetHipadabaNode(self->objectNode,"queue");
current = queue->child;
while(current != NULL){
tmp = current->next;
DeleteNodeData(current);
current = tmp;
}
queue->child = NULL;
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){
priv->isRunning = 0;
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){
priv->isRunning = 0;
return 0;
}
pos++;
work->value.v.intValue = pos;
NotifyHipadabaPar(work,priv->pCon);
if(pos >= max->value.v.intValue){
priv->isRunning = 0;
return 0;
}
return 1;
}
/*---------------------------------------------------------------------------*/
static int Start(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
pHdb par[], int nPar){
pHdbQueue priv = (pHdbQueue)self->pPrivate;
priv->iStop = 0;
priv->pCon = pCon;
if(priv->isRunning == 1){
SCWrite(pCon,"ERROR: Hdbqueue is already running",eError);
return 0;
}
priv->isRunning = 1;
TaskRegister(pServ->pTasker,
QueueTask,
NULL,
NULL,
self,
10);
return 1;
}
/*---------------------------------------------------------------------------*/
static int Restart(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
pHdb par[], int nPar){
pHdbQueue priv = (pHdbQueue)self->pPrivate;
pHdb maxCurrent = NULL;
maxCurrent = GetHipadabaNode(self->objectNode,"control/currentEntry");
if(maxCurrent != NULL){
maxCurrent->value.v.intValue = 0;
NotifyHipadabaPar(maxCurrent,pCon);
}
return Start(self,pCon,commandNode,par,nPar);
}
/*---------------------------------------------------------------------------*/
static int Stop(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
pHdb par[], int nPar){
pHdbQueue priv = (pHdbQueue)self->pPrivate;
priv->iStop = 1;
return 1;
}
/*----------------------------------------------------------------------------*/
static int Move(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
pHdb par[], int nPar){
pHdb moveNode = NULL;
pHdb insertNode = NULL;
pHdb prevNode = NULL, queueNode = NULL;
pHdb tmp;
char name[80];
pHdbQueue priv = (pHdbQueue)self->pPrivate;
if(priv->isRunning == 1){
SCWrite(pCon,"ERROR: cannot move while running",eError);
return 0;
}
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 = MakeSICSFunc(EnqueFunc);
n = MakeSICSHdbPar("enqueue",usUser, funcValue);
AddSICSHdbPar(n,"description",usUser,textValue);
AddHipadabaChild(obj,n,NULL);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
funcValue = MakeSICSFunc(AddCmdData);
n = MakeSICSHdbPar("addcommand",usUser, funcValue);
AddSICSHdbPar(n,"command",usUser,textValue);
AddHipadabaChild(obj,n,NULL);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
funcValue = MakeSICSFunc(Dequeue);
n = MakeSICSHdbPar("dequeue",usUser,funcValue);
AddHipadabaChild(obj,n,NULL);
AddSICSHdbPar(n,"index",usUser,intValue);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
funcValue = MakeSICSFunc(Clean);
n = MakeSICSHdbPar("clean",usUser, funcValue);
AddHipadabaChild(obj,n,NULL);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
funcValue = MakeSICSFunc(CleanAll);
n = MakeSICSHdbPar("cleanall",usUser, funcValue);
AddHipadabaChild(obj,n,NULL);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
funcValue = MakeSICSFunc(Start);
n = MakeSICSHdbPar("start",usUser, funcValue);
AddHipadabaChild(obj,n,NULL);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
funcValue = MakeSICSFunc(Restart);
n = MakeSICSHdbPar("restart",usUser, funcValue);
AddHipadabaChild(obj,n,NULL);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
funcValue = MakeSICSFunc(Stop);
n = MakeSICSHdbPar("stop",usUser, funcValue);
AddHipadabaChild(obj,n,NULL);
AppendHipadabaCallback(n,HCBSET,MakeSICSFuncCallback(self));
funcValue = MakeSICSFunc(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;
}