diff --git a/src/dbStatic/dbBase.h b/src/dbStatic/dbBase.h index d5a9f637c..de0060de8 100644 --- a/src/dbStatic/dbBase.h +++ b/src/dbStatic/dbBase.h @@ -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 diff --git a/src/dbStatic/dbLex.l b/src/dbStatic/dbLex.l index ccb7f1726..89764aa9c 100644 --- a/src/dbStatic/dbLex.l +++ b/src/dbStatic/dbLex.l @@ -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); +} %% diff --git a/src/dbStatic/dbLexRoutines.c b/src/dbStatic/dbLexRoutines.c index 629aaae91..216827c2a 100644 --- a/src/dbStatic/dbLexRoutines.c +++ b/src/dbStatic/dbLexRoutines.c @@ -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; diff --git a/src/dbStatic/dbStaticLib.c b/src/dbStatic/dbStaticLib.c index d6e73c030..2c2df6c46 100644 --- a/src/dbStatic/dbStaticLib.c +++ b/src/dbStatic/dbStaticLib.c @@ -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) { diff --git a/src/dbStatic/dbStaticLib.h b/src/dbStatic/dbStaticLib.h index e6b2a9a64..8acb23a1c 100644 --- a/src/dbStatic/dbStaticLib.h +++ b/src/dbStatic/dbStaticLib.h @@ -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*/ diff --git a/src/dbStatic/dbToRecordtypeH.c b/src/dbStatic/dbToRecordtypeH.c index 4bc85b288..d56fd28a8 100644 --- a/src/dbStatic/dbToRecordtypeH.c +++ b/src/dbStatic/dbToRecordtypeH.c @@ -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); diff --git a/src/dbStatic/dbYacc.y b/src/dbStatic/dbYacc.y index 63af2f6c5..5731b3881 100644 --- a/src/dbStatic/dbYacc.y +++ b/src/dbStatic/dbYacc.y @@ -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 tokenSTRING +%token 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 ;