Files
sics/hdbqueue.c
koennecke 91d4af0541 - Adapted indenation to new agreed upon system
- Added support for second generation scriptcontext based counter
2009-02-13 09:00:03 +00:00

525 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;
}