This is our new RELEASE-4_0 branch which was taken from ansto/93d9a7c Conflicts: .gitignore SICSmain.c asynnet.c confvirtualmot.c counter.c devexec.c drive.c event.h exebuf.c exeman.c histmem.c interface.h motor.c motorlist.c motorsec.c multicounter.c napi.c napi.h napi4.c network.c nwatch.c nxscript.c nxxml.c nxxml.h ofac.c reflist.c scan.c sicshipadaba.c sicsobj.c site_ansto/docs/Copyright.txt site_ansto/instrument/lyrebird/config/tasmad/sicscommon/nxsupport.tcl site_ansto/instrument/lyrebird/config/tasmad/taspub_sics/tasscript.tcl statusfile.c tasdrive.c tasub.c tasub.h tasublib.c tasublib.h
522 lines
14 KiB
C
522 lines
14 KiB
C
/**
|
|
* Hdbtable is a more generic implementation for a table based on a Hipadaba
|
|
* tree structure. This table will be used at various instances in SICS. The general
|
|
* approach is that there is a child node called template whose children will be
|
|
* the nodes describing each column. Another entry called data will hold the
|
|
* rows of the table. Each row is a clone of the template. The result is
|
|
* an inefficient mapping of a table into a tree. But then, for smaller tables this
|
|
* is good enough and fits nicely into the Hipadaba and gumtree schemes. This file
|
|
* provides a couple of commands to deal with such tables. A user of this module will
|
|
* have to add content to the template first. And then run readtemplate in order
|
|
* to activate the new structure.
|
|
*
|
|
* I use a descriptor key called rowcount for the row ID management rather then
|
|
* the private data structure. This leaves clients of this module to use the
|
|
* private data structure at will.
|
|
*
|
|
* copyright: see file COPYRIGHT
|
|
*
|
|
* Mark Koennecke, March 2009
|
|
*
|
|
* Added CountTblCmd
|
|
*
|
|
* Mark Koennecke, march 2013
|
|
*/
|
|
#include <stdlib.h>
|
|
#include "sicshipadaba.h"
|
|
#include <hdbtable.h>
|
|
/*------------------------------------------------------------------------*/
|
|
int SaveHdbTable(void *data, char *name, FILE * fd)
|
|
{
|
|
pSICSOBJ self = (pSICSOBJ) data;
|
|
pHdb datanode, row, child;
|
|
pDynString val;
|
|
|
|
datanode = GetHipadabaNode(self->objectNode,"data");
|
|
assert(datanode != NULL);
|
|
row = datanode->child;
|
|
fprintf(fd,"%s clear\n", name);
|
|
while(row != NULL){
|
|
fprintf(fd,"%s addrow ", name);
|
|
child = row->child;
|
|
while(child != NULL){
|
|
val = formatValue(child->value, child);
|
|
if(val != NULL){
|
|
fprintf(fd," %s", GetCharArray(val));
|
|
DeleteDynString(val);
|
|
}
|
|
child = child->next;
|
|
}
|
|
fprintf(fd,"\n");
|
|
row = row->next;
|
|
}
|
|
return 1;
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
static int ClearTblCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
|
|
pHdb par[], int nPar)
|
|
{
|
|
pHdb node, child, tmp;
|
|
|
|
node = GetHipadabaNode(self->objectNode,"data");
|
|
if(node != NULL){
|
|
if(CountHdbChildren(node) < 1){
|
|
return 1;
|
|
}
|
|
child = node->child;
|
|
while(child != NULL){
|
|
tmp = child;
|
|
child = child->next;
|
|
DeleteNodeData(tmp);
|
|
}
|
|
}
|
|
node->child = NULL;
|
|
SendTreeChangeMessage(node,pCon);
|
|
SetDescriptorKey(self->pDes,"rowcount","0");
|
|
if(pCon != NULL){
|
|
SCparChange(pCon);
|
|
}
|
|
return 1;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
int CountTblCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
|
|
pHdb par[], int nPar)
|
|
{
|
|
pHdb node;
|
|
int nRows = 0;
|
|
|
|
node = GetHipadabaNode(self->objectNode,"data");
|
|
if(node != NULL){
|
|
nRows = CountHdbChildren(node);
|
|
}
|
|
SCPrintf(pCon,eValue,"rows = %d", nRows);
|
|
return 1;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
static int AddTblRowCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
|
|
pHdb par[], int nPar)
|
|
{
|
|
int count;
|
|
char *ct, number[10];
|
|
pHdb row, val, child, template;
|
|
|
|
ct = GetDescriptorKey(self->pDes,"rowcount");
|
|
count = atoi(ct);
|
|
snprintf(number,10,"%4.4d", count);
|
|
row = MakeHipadabaNode(number,HIPNONE,1);
|
|
if(row == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory in AddTblRow", eError);
|
|
return 0;
|
|
}
|
|
count++;
|
|
snprintf(number,10,"%d",count);
|
|
SetDescriptorKey(self->pDes,"rowcount",number);
|
|
SetHdbProperty(row,"__save","true");
|
|
|
|
template = GetHipadabaNode(self->objectNode,"template");
|
|
assert(template != NULL);
|
|
child = template->child;
|
|
count = 0;
|
|
while(child != NULL){
|
|
val = MakeSICSHdbPar(child->name,usUser,
|
|
makeHdbValue(child->value.dataType, child->value.arrayLength));
|
|
if(count < nPar){
|
|
UpdateHipadabaPar(val,par[count]->value,pCon);
|
|
}
|
|
AddHipadabaChild(row,val, pCon);
|
|
SetHdbProperty(val,"__save","true");
|
|
count++;
|
|
child = child->next;
|
|
}
|
|
child = GetHipadabaNode(self->objectNode,"data");
|
|
assert(child != NULL);
|
|
AddHipadabaChild(child,row, pCon);
|
|
SendTreeChangeMessage(child,pCon);
|
|
if(pCon != NULL){
|
|
SCparChange(pCon);
|
|
}
|
|
return 1;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
static int RepTblRowCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
|
|
pHdb par[], int nPar)
|
|
{
|
|
int count;
|
|
char path[132];
|
|
pHdb row, val, child;
|
|
|
|
if(nPar < 1) {
|
|
SCPrintf(pCon,eError,"ERROR: no parameters found to reprow");
|
|
return 0;
|
|
}
|
|
snprintf(path,131,"data/%s", par[0]->value.v.text);
|
|
row = GetHipadabaNode(self->objectNode,path);
|
|
if(row == NULL){
|
|
SCPrintf(pCon,eError,"ERROR: row with ID %s not found", par[0]->value.v.text);
|
|
return 0;
|
|
}
|
|
|
|
child = row->child;
|
|
count = 1;
|
|
while(child != NULL && count < nPar){
|
|
if(count < nPar){
|
|
UpdateHipadabaPar(child,par[count]->value,pCon);
|
|
}
|
|
count++;
|
|
child = child->next;
|
|
}
|
|
if(pCon != NULL){
|
|
SCparChange(pCon);
|
|
}
|
|
return 1;
|
|
}
|
|
/*----------------------------------------------------------------------
|
|
* ReadTemplateCmd does something interesting: it rewrites the parameter
|
|
* lists of both addrow and reprow according to the template
|
|
* ---------------------------------------------------------------------*/
|
|
int ReadTableTemplate(pSICSOBJ self, SConnection *con)
|
|
{
|
|
pHdb node, template, child, cmd;
|
|
SConnection *pCon = con;
|
|
|
|
if(pCon == NULL){
|
|
pCon = pServ->dummyCon;
|
|
}
|
|
|
|
template = GetHipadabaNode(self->objectNode,"template");
|
|
assert(template != NULL);
|
|
|
|
/* mogrify addrow */
|
|
node = GetHipadabaNode(self->objectNode,"addrow");
|
|
if(node != NULL){
|
|
DeleteHipadabaNode(node,pCon);
|
|
}
|
|
|
|
cmd = AddSICSHdbPar(self->objectNode, "addrow", usUser,
|
|
MakeSICSFunc(AddTblRowCmd));
|
|
if(cmd == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory in ReadTemplateCmd",eError );
|
|
return 0;
|
|
}
|
|
SetHdbProperty(cmd,"type","command");
|
|
SetHdbProperty(cmd,"priv","user");
|
|
child = template->child;
|
|
while(child != NULL){
|
|
node = MakeSICSHdbPar(child->name, usUser,
|
|
makeHdbValue(child->value.dataType, child->value.arrayLength));
|
|
if(node == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory in ReadTemplateCmd",eError );
|
|
return 0;
|
|
}
|
|
AddHipadabaChild(cmd,node,pCon);
|
|
child = child->next;
|
|
}
|
|
|
|
/* mogrify reprow */
|
|
node = GetHipadabaNode(self->objectNode,"reprow");
|
|
if(node != NULL){
|
|
DeleteHipadabaNode(node,pCon);
|
|
}
|
|
cmd = AddSICSHdbPar(self->objectNode, "reprow", usUser,
|
|
MakeSICSFunc(RepTblRowCmd));
|
|
if(cmd == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory in ReadTemplateCmd",eError );
|
|
return 0;
|
|
}
|
|
SetHdbProperty(cmd,"type","command");
|
|
SetHdbProperty(cmd,"priv","user");
|
|
node = MakeSICSHdbPar("id",usUser, makeHdbValue(HIPTEXT,1));
|
|
AddHipadabaChild(cmd,node, pCon);
|
|
|
|
child = template->child;
|
|
while(child != NULL){
|
|
node = MakeSICSHdbPar(child->name, usUser,
|
|
makeHdbValue(child->value.dataType, child->value.arrayLength));
|
|
if(node == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory in ReadTemplateCmd",eError );
|
|
return 0;
|
|
}
|
|
AddHipadabaChild(cmd,node,pCon);
|
|
child = child->next;
|
|
}
|
|
return 1;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
static int ReadTemplateCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
|
|
pHdb par[], int nPar)
|
|
{
|
|
return ReadTableTemplate(self,pCon);
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
static int DelRowCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
|
|
pHdb par[], int nPar)
|
|
{
|
|
pHdb row = NULL, data;
|
|
char path[132];
|
|
|
|
if(nPar < 1){
|
|
SCWrite(pCon,"ERROR: need ID of row to kill",eError);
|
|
return 0;
|
|
}
|
|
snprintf(path,132,"data/%s",par[0]->value.v.text);
|
|
row = GetHipadabaNode(self->objectNode,path);
|
|
if(row == NULL){
|
|
SCPrintf(pCon,eError,"ERROR: row with ID %s not found", par[0]->value.v.text);
|
|
return 0;
|
|
}
|
|
data = row->mama;
|
|
DeleteHipadabaNode(row,pCon);
|
|
if(pCon != NULL){
|
|
SCparChange(pCon);
|
|
}
|
|
SendTreeChangeMessage(data,pCon);
|
|
SCSendOK(pCon);
|
|
return 1;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
static int GetRowCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
|
|
pHdb par[], int nPar)
|
|
{
|
|
pHdb row = NULL, child;
|
|
char path[132];
|
|
pDynString result, val;
|
|
|
|
if(nPar < 1){
|
|
SCWrite(pCon,"ERROR: need ID of row to read",eError);
|
|
return 0;
|
|
}
|
|
snprintf(path,132,"data/%s",par[0]->value.v.text);
|
|
row = GetHipadabaNode(self->objectNode,path);
|
|
if(row == NULL){
|
|
SCPrintf(pCon,eError,"ERROR: row with ID %s not found", par[0]->value.v.text);
|
|
return 0;
|
|
}
|
|
result = CreateDynString(128,128);
|
|
if(result == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory in GetRowCmd", eError);
|
|
return 0;
|
|
}
|
|
child = row->child;
|
|
while(child != NULL){
|
|
val = formatValue(child->value, child);
|
|
if(val != NULL){
|
|
DynStringConcat(result,GetCharArray(val));
|
|
if(child->next != NULL){
|
|
DynStringConcatChar(result,',');
|
|
}
|
|
DeleteDynString(val);
|
|
}
|
|
child = child->next;
|
|
}
|
|
SCWrite(pCon,GetCharArray(result),eValue);
|
|
DeleteDynString(result);
|
|
return 1;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
static int GetRowNoCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
|
|
pHdb par[], int nPar)
|
|
{
|
|
pHdb row = NULL, child, data;
|
|
int i, nodeNo;
|
|
char path[132];
|
|
pDynString result, val;
|
|
|
|
if(nPar < 1){
|
|
SCWrite(pCon,"ERROR: need index of row to read",eError);
|
|
return 0;
|
|
}
|
|
nodeNo = par[0]->value.v.intValue;
|
|
|
|
data = GetHipadabaNode(self->objectNode,"data");
|
|
assert(data != NULL);
|
|
row = data->child;
|
|
for(i = 0; i < nodeNo; i++){
|
|
row = row->next;
|
|
if(row == NULL){
|
|
SCPrintf(pCon,eError,"ERROR: row %d not found", nodeNo);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
result = CreateDynString(128,128);
|
|
if(result == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory in GetRowCmd", eError);
|
|
return 0;
|
|
}
|
|
child = row->child;
|
|
while(child != NULL){
|
|
val = formatValue(child->value, child);
|
|
if(val != NULL){
|
|
DynStringConcat(result,GetCharArray(val));
|
|
if(child->next != NULL){
|
|
DynStringConcatChar(result,',');
|
|
}
|
|
DeleteDynString(val);
|
|
}
|
|
child = child->next;
|
|
}
|
|
SCWrite(pCon,GetCharArray(result),eValue);
|
|
DeleteDynString(result);
|
|
return 1;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
static int ListTblCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode,
|
|
pHdb par[], int nPar)
|
|
{
|
|
pHdb node, row, child, data, template;
|
|
char buffer[20];
|
|
pDynString list = NULL, val;
|
|
|
|
list = CreateDynString(25,256);
|
|
if(list == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory in LisTblCmd", eError);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* create the list header
|
|
*/
|
|
DynStringConcat(list," ID");
|
|
template = GetHipadabaNode(self->objectNode,"template");
|
|
assert(template != NULL);
|
|
child = template->child;
|
|
while(child != NULL){
|
|
snprintf(buffer,20," %8s", child->name);
|
|
DynStringConcat(list,buffer);
|
|
child = child->next;
|
|
}
|
|
DynStringConcatChar(list,'\n');
|
|
|
|
data = GetHipadabaNode(self->objectNode,"data");
|
|
assert(data != NULL);
|
|
|
|
/*
|
|
* list the data
|
|
*/
|
|
row = data->child;
|
|
while(row != NULL){
|
|
snprintf(buffer,20," %8s", row->name);
|
|
DynStringConcat(list,buffer);
|
|
child = row->child;
|
|
while(child != NULL){
|
|
val = formatValue(child->value,child);
|
|
snprintf(buffer,20," %8s", GetCharArray(val));
|
|
DynStringConcat(list,buffer);
|
|
DeleteDynString(val);
|
|
child = child->next;
|
|
}
|
|
DynStringConcatChar(list,'\n');
|
|
row = row->next;
|
|
}
|
|
|
|
SCWrite(pCon,GetCharArray(list),eValue);
|
|
DeleteDynString(list);
|
|
return 1;
|
|
}
|
|
/*----------------------------------------------------------------------*/
|
|
pSICSOBJ MakeHdbTable(char *name, char *hdbclass)
|
|
{
|
|
pSICSOBJ result = NULL;
|
|
pHdb node, cmd;
|
|
|
|
result = MakeSICSOBJv(name,hdbclass,HIPNONE,usSpy);
|
|
if(result == NULL){
|
|
return NULL;
|
|
}
|
|
SetDescriptorKey(result->pDes,"rowcount","0");
|
|
SetHdbProperty(result->objectNode,"viewer","mountaingumui.TableViewer");
|
|
result->pDes->SaveStatus = SaveHdbTable;
|
|
|
|
node = MakeSICSHdbPar("template",usMugger,MakeHdbText("x,y"));
|
|
if(node == NULL){
|
|
return NULL;
|
|
}
|
|
SetHdbProperty(node,"__save","true");
|
|
|
|
AddHipadabaChild(result->objectNode,node,NULL);
|
|
node = MakeHipadabaNode("data",HIPNONE,1);
|
|
if(node == NULL){
|
|
return NULL;
|
|
}
|
|
SetHdbProperty(node,"__save","true");
|
|
AddHipadabaChild(result->objectNode,node,NULL);
|
|
|
|
cmd = AddSICSHdbPar(result->objectNode, "clear", usUser,
|
|
MakeSICSFunc(ClearTblCmd));
|
|
SetHdbProperty(cmd,"type","command");
|
|
SetHdbProperty(cmd,"priv","user");
|
|
|
|
cmd = AddSICSHdbPar(result->objectNode, "print", usUser,
|
|
MakeSICSFunc(ListTblCmd));
|
|
SetHdbProperty(cmd,"type","command");
|
|
SetHdbProperty(cmd,"priv","user");
|
|
|
|
cmd = AddSICSHdbPar(result->objectNode, "addrow", usUser,
|
|
MakeSICSFunc(AddTblRowCmd));
|
|
SetHdbProperty(cmd,"type","command");
|
|
SetHdbProperty(cmd,"priv","user");
|
|
|
|
cmd = AddSICSHdbPar(result->objectNode, "reprow", usUser,
|
|
MakeSICSFunc(RepTblRowCmd));
|
|
SetHdbProperty(cmd,"type","command");
|
|
SetHdbProperty(cmd,"priv","user");
|
|
|
|
cmd = AddSICSHdbPar(result->objectNode, "readtemplate", usUser,
|
|
MakeSICSFunc(ReadTemplateCmd));
|
|
|
|
cmd = AddSICSHdbPar(result->objectNode, "del", usUser,
|
|
MakeSICSFunc(DelRowCmd));
|
|
node = MakeHipadabaNode("id",HIPTEXT,1);
|
|
SetHdbProperty(cmd,"type","command");
|
|
SetHdbProperty(cmd,"priv","user");
|
|
SetHdbProperty(node,"priv","user");
|
|
AddHipadabaChild(cmd,node, NULL);
|
|
|
|
cmd = AddSICSHdbPar(result->objectNode, "get", usUser,
|
|
MakeSICSFunc(GetRowCmd));
|
|
SetHdbProperty(cmd,"type","command");
|
|
SetHdbProperty(cmd,"priv","user");
|
|
node = MakeHipadabaNode("id",HIPTEXT,1);
|
|
SetHdbProperty(node,"priv","user");
|
|
AddHipadabaChild(cmd,node, NULL);
|
|
|
|
cmd = AddSICSHdbPar(result->objectNode, "getno", usUser,
|
|
MakeSICSFunc(GetRowNoCmd));
|
|
SetHdbProperty(cmd,"type","command");
|
|
SetHdbProperty(cmd,"priv","user");
|
|
node = MakeHipadabaNode("id",HIPINT,1);
|
|
SetHdbProperty(node,"priv","user");
|
|
AddHipadabaChild(cmd,node, NULL);
|
|
|
|
cmd = AddSICSHdbPar(result->objectNode, "count", usSpy,
|
|
MakeSICSFunc(CountTblCmd));
|
|
|
|
return result;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
int HdbTableFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pSICSOBJ pNew = NULL;
|
|
int status;
|
|
|
|
if(argc < 2) {
|
|
SCWrite(pCon,"ERROR: need name of table to create", eError);
|
|
return 0;
|
|
}
|
|
|
|
pNew = MakeHdbTable(argv[1],"HdbTable");
|
|
if(pNew == NULL){
|
|
SCWrite(pCon,"ERROR: out of memory in MakeHdbTable", eError);
|
|
return 0;
|
|
}
|
|
|
|
status = AddCommand(pSics, argv[1], InterInvokeSICSOBJ, DefaultKill, pNew);
|
|
if (status != 1) {
|
|
SCWrite(pCon, "ERROR: duplicate HdbTable command not created", eError);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|