/** * 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 */ #include #include "sicshipadaba.h" #include /*------------------------------------------------------------------------*/ 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; } /*----------------------------------------------------------------------*/ 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); 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; }