Added support for 'info' items in database records - named strings that

are saved & loaded in the .db file, with an API for access at runtime and
the ability to associate a void* pointer with each at runtime.

Also added a capability to dbToRecordTypeH allowing a record type's .dbd
file to add lines to the generated .h file.  The C code should be placed
inside the recordtype's braces {} and each line must start with a '%'.
This facility is not currently accessible through a dbStaticLib API.
This commit is contained in:
Andrew Johnson
2000-08-09 21:38:34 +00:00
parent 086196b9f7
commit 16f572b06d
7 changed files with 283 additions and 38 deletions
+15
View File
@@ -107,10 +107,18 @@ typedef struct dbFldDes{ /* field description */
short offset; /*Offset in bytes from beginning of record*/
}dbFldDes;
typedef struct dbInfoNode { /*non-field per-record information*/
ELLNODE node;
char *name;
char *string;
void *pointer;
}dbInfoNode;
typedef struct dbRecordNode {
ELLNODE node;
void *precord;
char *recordname;
ELLLIST infoList; /*LIST head of info nodes*/
int visible;
}dbRecordNode;
@@ -124,11 +132,17 @@ typedef struct dbRecordAttribute {
char value[MAX_STRING_SIZE];
}dbRecordAttribute;
typedef struct dbCdefText {
ELLNODE node;
char *text;
}dbCdefText;
typedef struct dbRecordType {
ELLNODE node;
ELLLIST attributeList; /*LIST head of attributes*/
ELLLIST recList; /*LIST head of sorted dbRecordNodes*/
ELLLIST devList; /*List of associated device support*/
ELLLIST cdefList; /*LIST of Cdef text items*/
char *name;
short no_fields; /* number of fields defined */
short no_prompt; /* number of fields to configure*/
@@ -153,5 +167,6 @@ typedef struct dbBase {
void *ppvd; /* pointer to process variable directory*/
void *pgpHash; /*General purpose Hash Table*/
short ignoreMissingMenus;
short loadCdefs;
}dbBase;
#endif
+43 -34
View File
@@ -18,24 +18,25 @@ static int yyreset(void)
%%
"include" {return(tokenINCLUDE);}
"path" {return(tokenPATH);}
"addpath" {return(tokenADDPATH);}
"menu" {return(tokenMENU);}
"choice" {return(tokenCHOICE);}
"recordtype" {return(tokenRECORDTYPE);}
"field" {return(tokenFIELD);}
"device" {return(tokenDEVICE);}
"driver" {return(tokenDRIVER);}
"breaktable" {return(tokenBREAKTABLE);}
"record" {return(tokenRECORD);}
"grecord" {return(tokenGRECORD);}
"include" return(tokenINCLUDE);
"path" return(tokenPATH);
"addpath" return(tokenADDPATH);
"menu" return(tokenMENU);
"choice" return(tokenCHOICE);
"recordtype" return(tokenRECORDTYPE);
"field" return(tokenFIELD);
"device" return(tokenDEVICE);
"driver" return(tokenDRIVER);
"breaktable" return(tokenBREAKTABLE);
"record" return(tokenRECORD);
"grecord" return(tokenGRECORD);
"info" return(tokenINFO);
[0-9]+ { /*integer number*/
yylval.Str = (char *)dbmfMalloc(strlen(yytext)+1);
strcpy(yylval.Str,yytext);
return(tokenSTRING);
}
}
-?(([0-9]+)|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?) { /*real number*/
yylval.Str = (char *)dbmfMalloc(strlen(yytext)+1);
@@ -51,29 +52,37 @@ static int yyreset(void)
}
\"{string}*\" { /*quoted string*/
yylval.Str = (char *)dbmfMalloc(strlen(yytext)+1);
strcpy(yylval.Str,yytext+1);
yylval.Str[strlen(yylval.Str)-1] = '\0';
return(tokenSTRING);
int nchars=strlen(yytext);
yylval.Str = (char *)dbmfMalloc(nchars-1);
strncpy(yylval.Str, yytext+1, nchars-2);
yylval.Str[nchars-2] = '\0';
return(tokenSTRING);
}
"{" { return(yytext[0]); }
"}" { return(yytext[0]); }
"(" { return(yytext[0]); }
")" { return(yytext[0]); }
"," { return(yytext[0]); }
#.* { ;}
%.* { /*C definition in recordtype*/
yylval.Str = (char *)dbmfMalloc(strlen(yytext));
strcpy(yylval.Str,yytext+1);
return(tokenCDEFS);
}
"{" return(yytext[0]);
"}" return(yytext[0]);
"(" return(yytext[0]);
")" return(yytext[0]);
"," return(yytext[0]);
\#.* ;
[ \t\r] ;
\n { ;}
. {
char message[20];
YY_BUFFER_STATE *dummy=0;
sprintf(message,"invalid character '%c'",yytext[0]);
yyerror(message);
/*The following suppresses compiler warning messages*/
if(FALSE) yyunput('c',message);
if(FALSE) yy_switch_to_buffer(*dummy);
}
\n ;
. {
char message[20];
YY_BUFFER_STATE *dummy=0;
sprintf(message,"invalid character '%c'",yytext[0]);
yyerror(message);
/*The following suppresses compiler warning messages*/
if(FALSE) yyunput('c',message);
if(FALSE) yy_switch_to_buffer(*dummy);
}
%%
+34
View File
@@ -467,6 +467,7 @@ static void dbRecordtypeHead(char *name)
}
pdbRecordType = dbCalloc(1,sizeof(dbRecordType));
pdbRecordType->name = strduplicate(name);
if (pdbbase->loadCdefs) ellInit(&pdbRecordType->cdefList);
if(ellCount(&tempList))
yyerrorAbort("dbRecordtypeHead tempList not empty");
allocTemp(pdbRecordType);
@@ -582,6 +583,22 @@ static void dbRecordtypeFieldItem(char *name,char *value)
}
}
static void dbRecordtypeCdef(char *text) {
dbCdefText *pdbCdef;
tempListNode *ptempListNode;
dbRecordType *pdbRecordType;
if (!pdbbase->loadCdefs || duplicate) return;
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbRecordType = ptempListNode->item;
pdbCdef = dbCalloc(1,sizeof(dbCdefText));
if (text[0] == ' ') text++; /* strip leading space if present */
pdbCdef->text = strduplicate(text);
ellAdd(&pdbRecordType->cdefList, &pdbCdef->node);
return;
}
static void dbRecordtypeBody(void)
{
dbRecordType *pdbRecordType;
@@ -866,6 +883,23 @@ static void dbRecordField(char *name,char *value)
}
}
static void dbRecordInfo(char *name, char *value)
{
DBENTRY *pdbentry;
tempListNode *ptempListNode;
long status;
if(duplicate) return;
ptempListNode = (tempListNode *)ellFirst(&tempList);
pdbentry = ptempListNode->item;
status = dbPutInfo(pdbentry,name,value);
if(status) {
errMessage(status,"");
yyerror(NULL);
return;
}
}
static void dbRecordBody(void)
{
DBENTRY *pdbentry;
+154
View File
@@ -923,6 +923,12 @@ long epicsShareAPI dbWriteRecordFP(DBBASE *pdbbase,FILE *fp,char *precordTypenam
}
status=dbNextField(pdbentry,dctonly);
}
status = dbFirstInfo(pdbentry);
while(!status) {
fprintf(fp,"\tinfo(\"%s\",\"%s\")\n",
dbGetInfoName(pdbentry), dbGetInfoString(pdbentry));
status=dbNextInfo(pdbentry);
}
fprintf(fp,"}\n");
status = dbNextRecord(pdbentry);
}
@@ -1441,6 +1447,7 @@ long epicsShareAPI dbCreateRecord(DBENTRY *pdbentry,char *precordName)
pdbentry->precnode = pNewRecNode;
if((status = dbAllocRecord(pdbentry,precordName))) return(status);
pNewRecNode->recordname = dbRecordName(pdbentry);
ellInit(&pNewRecNode->infoList);
/* install record node in list in sorted postion */
status = dbFirstRecord(pdbentry);
while(status==0) {
@@ -1471,6 +1478,9 @@ long epicsShareAPI dbDeleteRecord(DBENTRY *pdbentry)
preclist = &precordType->recList;
ellDelete(preclist,&precnode->node);
dbPvdDelete(pdbbase,precnode);
while (!dbFirstInfo(pdbentry)) {
dbDeleteInfo(pdbentry);
}
if((status = dbFreeRecord(pdbentry))) return(status);
free((void *)precnode);
pdbentry->precnode = NULL;
@@ -1680,6 +1690,13 @@ long epicsShareAPI dbCopyRecord(DBENTRY *pdbentry,char *newRecordName,int overWr
exit(1);
}
}
/*Copy the info strings too*/
status = dbFirstInfo(pdbentry);
while (!status) {
status = dbPutInfo(&dbentry, dbGetInfoName(pdbentry), dbGetInfoString(pdbentry));
if (status) return (status);
status = dbNextInfo(pdbentry);
}
/*Leave pdbentry pointing to newRecordName*/
return(dbFindRecord(pdbentry,newRecordName));
}
@@ -2484,6 +2501,143 @@ char *epicsShareAPI dbGetRange(DBENTRY *pdbentry)
strcpy(message,"Not a valid field type");
return (message);
}
long epicsShareAPI dbFirstInfo(DBENTRY *pdbentry)
{
dbRecordNode *precnode = pdbentry->precnode;
pdbentry->pinfonode = NULL;
if (!precnode) return (S_dbLib_recNotFound);
pdbentry->pinfonode = (dbInfoNode *)ellFirst(&precnode->infoList);
return (pdbentry->pinfonode ? 0 : S_dbLib_infoNotFound);
}
long epicsShareAPI dbNextInfo(DBENTRY *pdbentry)
{
dbRecordNode *precnode = pdbentry->precnode;
dbInfoNode *pinfo;
if (!precnode) return (S_dbLib_recNotFound);
pinfo = pdbentry->pinfonode;
if (!pinfo) return (S_dbLib_infoNotFound);
pinfo = (dbInfoNode *)ellNext(&pinfo->node);
pdbentry->pinfonode = pinfo;
return (pinfo ? 0 : S_dbLib_infoNotFound);
}
long epicsShareAPI dbFindInfo(DBENTRY *pdbentry,const char *name)
{
dbRecordNode *precnode = pdbentry->precnode;
dbInfoNode *pinfo;
pdbentry->pinfonode = NULL;
if (!precnode) return(S_dbLib_recNotFound);
pinfo = (dbInfoNode *)ellFirst(&precnode->infoList);
while (pinfo) {
if (!strcmp(pinfo->name, name)) {
pdbentry->pinfonode = pinfo;
return (0);
}
pinfo = (dbInfoNode *)ellNext(&pinfo->node);
}
return (S_dbLib_infoNotFound);
}
long epicsShareAPI dbDeleteInfo(DBENTRY *pdbentry)
{
dbRecordNode *precnode = pdbentry->precnode;
dbInfoNode *pinfo = pdbentry->pinfonode;
if (!precnode) return (S_dbLib_recNotFound);
if (!pinfo) return (S_dbLib_infoNotFound);
ellDelete(&precnode->infoList,&pinfo->node);
free(pinfo->name);
free(pinfo->string);
free(pinfo);
pdbentry->pinfonode = NULL;
return (0);
}
const char * epicsShareAPI dbGetInfoName(DBENTRY *pdbentry)
{
dbInfoNode *pinfo = pdbentry->pinfonode;
if (!pinfo) return (NULL);
return (pinfo->name);
}
const char * epicsShareAPI dbGetInfoString(DBENTRY *pdbentry)
{
dbInfoNode *pinfo = pdbentry->pinfonode;
if (!pinfo) return (NULL);
return (pinfo->string);
}
long epicsShareAPI dbPutInfoString(DBENTRY *pdbentry,const char *string)
{
dbInfoNode *pinfo = pdbentry->pinfonode;
char *newstring;
if (!pinfo) return (S_dbLib_infoNotFound);
newstring = realloc(pinfo->string,1+strlen(string));
if (!newstring) return (S_dbLib_outMem);
strcpy(newstring, string);
pinfo->string = newstring;
return (0);
}
long epicsShareAPI dbPutInfoPointer(DBENTRY *pdbentry, void *pointer)
{
dbInfoNode *pinfo = pdbentry->pinfonode;
if (!pinfo) return (S_dbLib_infoNotFound);
pinfo->pointer = pointer;
return (0);
}
const char * epicsShareAPI dbGetInfoPointer(DBENTRY *pdbentry)
{
dbInfoNode *pinfo = pdbentry->pinfonode;
if (!pinfo) return (NULL);
return (pinfo->pointer);
}
const char * epicsShareAPI dbGetInfo(DBENTRY *pdbentry,const char *name)
{
dbFindInfo(pdbentry, name);
return (dbGetInfoString(pdbentry));
}
long epicsShareAPI dbPutInfo(DBENTRY *pdbentry,const char *name,const char *string)
{
dbInfoNode *pinfo;
dbRecordNode *precnode = pdbentry->precnode;
if (!precnode) return (S_dbLib_recNotFound);
dbFindInfo(pdbentry, name);
pinfo = pdbentry->pinfonode;
if (pinfo) return (dbPutInfoString(pdbentry, string));
/*Create new info node*/
pinfo = calloc(1,sizeof(dbInfoNode));
if (!pinfo) return (S_dbLib_outMem);
pinfo->name = calloc(1,1+strlen(name));
if (!pinfo->name) {
free(pinfo);
return (S_dbLib_outMem);
}
strcpy(pinfo->name, name);
pinfo->string = calloc(1,1+strlen(string));
if (!pinfo->string) {
free(pinfo->name);
free(pinfo);
return (S_dbLib_outMem);
}
strcpy(pinfo->string, string);
ellAdd(&precnode->infoList,&pinfo->node);
pdbentry->pinfonode = pinfo;
return (0);
}
brkTable * epicsShareAPI dbFindBrkTable(dbBase *pdbbase,char *name)
{
+16 -1
View File
@@ -65,6 +65,7 @@ typedef struct{
dbRecordType *precordType;
dbFldDes *pflddes;
dbRecordNode *precnode;
dbInfoNode *pinfonode;
void *pfield;
char *message;
short indfield;
@@ -159,6 +160,18 @@ epicsShareFunc char * epicsShareAPI dbVerify(DBENTRY *pdbentry,char *pstring);
epicsShareFunc char * epicsShareAPI dbGetRange(DBENTRY *pdbentry);
epicsShareFunc int epicsShareAPI dbIsDefaultValue(DBENTRY *pdbentry);
epicsShareFunc long epicsShareAPI dbFirstInfo(DBENTRY *pdbentry);
epicsShareFunc long epicsShareAPI dbNextInfo(DBENTRY *pdbentry);
epicsShareFunc long epicsShareAPI dbFindInfo(DBENTRY *pdbentry,const char *name);
epicsShareFunc long epicsShareAPI dbDeleteInfo(DBENTRY *pdbentry);
epicsShareFunc const char * epicsShareAPI dbGetInfoName(DBENTRY *pdbentry);
epicsShareFunc const char * epicsShareAPI dbGetInfoString(DBENTRY *pdbentry);
epicsShareFunc long epicsShareAPI dbPutInfoString(DBENTRY *pdbentry,const char *string);
epicsShareFunc long epicsShareAPI dbPutInfoPointer(DBENTRY *pdbentry, void *pointer);
epicsShareFunc const char * epicsShareAPI dbGetInfoPointer(DBENTRY *pdbentry);
epicsShareFunc const char * epicsShareAPI dbGetInfo(DBENTRY *pdbentry,const char *name);
epicsShareFunc long epicsShareAPI dbPutInfo(DBENTRY *pdbentry,const char *name,const char *string);
epicsShareFunc brkTable * epicsShareAPI dbFindBrkTable(DBBASE *pdbbase,char *name);
epicsShareFunc dbMenu * epicsShareAPI dbFindMenu(DBBASE *pdbbase,char *name);
@@ -196,7 +209,7 @@ epicsShareFunc void epicsShareAPI dbPvdDump(DBBASE *pdbbase,int verbose);
epicsShareFunc void epicsShareAPI dbReportDeviceConfig(DBBASE *pdbbase,FILE *report);
/* Misc useful routines*/
/*general purpose allocation routines to invoke calloc and maloc */
/*general purpose allocation routines to invoke calloc and malloc */
/* NOTE: These routines do NOT return if they fail. */
epicsShareFunc void * epicsShareAPI dbCalloc(size_t nobj,size_t size);
epicsShareFunc void * epicsShareAPI dbMalloc(size_t size);
@@ -217,4 +230,6 @@ extern int dbStaticDebug;
#define S_dbLib_strLen (M_dbLib|21) /*String is too long*/
#define S_dbLib_noSizeOffset (M_dbLib|23) /*Missing SizeOffset Routine - No record support?*/
#define S_dbLib_noForm (M_dbLib|25) /*dbAllocForm was not called*/
#define S_dbLib_outMem (M_dbLib|27) /*Out of memory*/
#define S_dbLib_infoNotFound (M_dbLib|29) /*Info item Not Found*/
#endif /*INCdbStaticLibh*/
+7
View File
@@ -42,6 +42,7 @@ int main(int argc,char **argv)
dbMenu *pdbMenu;
dbRecordType *pdbRecordType;
dbFldDes *pdbFldDes;
dbCdefText *pdbCdef;
int isdbCommonRecord = FALSE;
char *plastSlash;
int strip;
@@ -117,6 +118,7 @@ int main(int argc,char **argv)
}
pdbbase = dbAllocBase();
pdbbase->ignoreMissingMenus = TRUE;
pdbbase->loadCdefs = TRUE;
status = dbReadDatabase(&pdbbase,argv[1],path,sub);
if(status) {
fprintf(stderr,"Terminal error For input file %s\n",argv[1]);
@@ -221,6 +223,11 @@ int main(int argc,char **argv)
fprintf(outFile,"#define %sRecord%s\t%d\n",
pdbRecordType->name,pdbFldDes->name,pdbFldDes->indRecordType);
}
pdbCdef = (dbCdefText *)ellFirst(&pdbRecordType->cdefList);
while (pdbCdef) {
fprintf(outFile,"%s\n",pdbCdef->text);
pdbCdef = (dbCdefText *)ellNext(&pdbCdef->node);
}
}
fprintf(outFile,"#endif /*INC%sH*/\n",pdbRecordType->name);
pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node);
+14 -3
View File
@@ -10,10 +10,11 @@ static int yyAbort = 0;
%start database
%token tokenINCLUDE tokenPATH tokenADDPATH
%token tokenMENU tokenCHOICE tokenRECORDTYPE tokenFIELD
%token tokenMENU tokenCHOICE tokenRECORDTYPE
%token tokenFIELD tokenINFO
%token tokenDEVICE tokenDRIVER tokenBREAKTABLE
%token tokenRECORD tokenGRECORD
%token <Str> tokenSTRING
%token <Str> tokenSTRING tokenCDEFS
%union
{
@@ -88,9 +89,14 @@ recordtype_body: '{' recordtype_field_list '}'
};
recordtype_field_list: recordtype_field_list recordtype_field
| recordtype_field;
| recordtype_field;
recordtype_field: tokenFIELD recordtype_field_head recordtype_field_body
| tokenCDEFS
{
if(dbStaticDebug>2) printf("recordtype_cdef %s", $1);
dbRecordtypeCdef($1);
}
| include ;
recordtype_field_head: '(' tokenSTRING ',' tokenSTRING ')'
@@ -191,6 +197,11 @@ record_field: tokenFIELD '(' tokenSTRING ',' tokenSTRING ')'
{
if(dbStaticDebug>2) printf("record_field %s %s\n",$3,$5);
dbRecordField($3,$5); dbmfFree($3); dbmfFree($5);
}
| tokenINFO '(' tokenSTRING ',' tokenSTRING ')'
{
if(dbStaticDebug>2) printf("record_info %s %s\n",$3,$5);
dbRecordInfo($3,$5); dbmfFree($3); dbmfFree($5);
}
| include ;