From ed4a2972d6d641d159800fabded28175269920f8 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 25 Mar 2009 23:02:28 +0000 Subject: [PATCH] Long string support: In dbStatic, split record and field search to make parsing easier. In dbAccess, '$' field name suffix makes field an array of DBF_CHAR. --- src/db/dbAccess.c | 103 +++++++++++-------- src/dbStatic/dbStaticLib.c | 204 ++++++++++++++++++++++--------------- src/dbStatic/dbStaticLib.h | 53 +++++----- 3 files changed, 213 insertions(+), 147 deletions(-) diff --git a/src/db/dbAccess.c b/src/db/dbAccess.c index cb5a0fa64..5592a7f3c 100644 --- a/src/db/dbAccess.c +++ b/src/db/dbAccess.c @@ -652,30 +652,51 @@ long epicsShareAPI dbNameToAddr(const char *pname, DBADDR *paddr) dbFldDes *pflddes; struct rset *prset; long status = 0; + long no_elements = 1; + short dbfType, dbrType; if (!pname || !*pname || !pdbbase) return S_db_notFound; dbInitEntry(pdbbase, &dbEntry); - status = dbFindRecord(&dbEntry, pname); - if (!status && !dbEntry.pfield) - status = dbFindField(&dbEntry, "VAL"); - if (status) { - dbFinishEntry(&dbEntry); - return status; - } + status = dbFindRecordPart(&dbEntry, &pname); + if (status) goto finish; + + if (*pname == '.') ++pname; + status = dbFindFieldPart(&dbEntry, &pname); + if (status == S_dbLib_fieldNotFound) + status = dbGetAttributePart(&dbEntry, &pname); + if (status) goto finish; paddr->precord = dbEntry.precnode->precord; paddr->pfield = dbEntry.pfield; pflddes = dbEntry.pflddes; - dbFinishEntry(&dbEntry); - paddr->pfldDes = pflddes; - paddr->field_type = pflddes->field_type; - paddr->dbr_field_type = mapDBFToDBR[pflddes->field_type]; - paddr->field_size = pflddes->size; - paddr->special = pflddes->special; - paddr->no_elements = 1; + dbfType = pflddes->field_type; + dbrType = mapDBFToDBR[dbfType]; + + if (*pname++ == '$') { + /* Some field types can be accessed as char arrays */ + if (dbfType == DBF_STRING) { + dbfType = DBF_CHAR; + dbrType = DBR_CHAR; + no_elements = pflddes->size; + } else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) { + /* Clients see a char array, but keep original dbfType */ + dbrType = DBR_CHAR; + no_elements = PVNAME_STRINGSZ + 12; + } else { + status = S_dbLib_fieldNotFound; + goto finish; + } + } + + paddr->pfldDes = pflddes; + paddr->field_type = dbfType; + paddr->dbr_field_type = dbrType; + paddr->field_size = pflddes->size; + paddr->special = pflddes->special; + paddr->no_elements = no_elements; if ((paddr->special == SPC_DBADDR) && (prset = dbGetRset(paddr)) && @@ -685,6 +706,9 @@ long epicsShareAPI dbNameToAddr(const char *pname, DBADDR *paddr) * dbr_field_type, field_size, and/or special. */ status = prset->cvt_dbaddr(paddr); + +finish: + dbFinishEntry(&dbEntry); return status; } @@ -740,12 +764,10 @@ unsigned dbNameSizeOfPV ( const dbAddr * paddr ) return recNameLen + fieldNameLen + 1; } -long epicsShareAPI dbValueSize( - short dbr_type -) +long epicsShareAPI dbValueSize(short dbr_type) { - /* sizes for value associated with each DBR request type */ - static long size[] = { + /* sizes for value associated with each DBR request type */ + static long size[] = { MAX_STRING_SIZE, /* STRING */ sizeof(epicsInt8), /* CHAR */ sizeof(epicsUInt8), /* UCHAR */ @@ -757,30 +779,26 @@ long epicsShareAPI dbValueSize( sizeof(epicsFloat64), /* DOUBLE */ sizeof(epicsEnum16)}; /* ENUM */ - return(size[dbr_type]); + return(size[dbr_type]); } -long epicsShareAPI dbBufferSize( - short dbr_type, - long options, - long no_elements -) +long epicsShareAPI dbBufferSize(short dbr_type, long options, long no_elements) { long nbytes=0; nbytes += dbValueSize(dbr_type) * no_elements; - if(options & DBR_STATUS) nbytes += dbr_status_size; - if(options & DBR_UNITS) nbytes += dbr_units_size; - if(options & DBR_PRECISION) nbytes += dbr_precision_size; - if(options & DBR_TIME) nbytes += dbr_time_size; - if(options & DBR_ENUM_STRS) nbytes += dbr_enumStrs_size; - if(options & DBR_GR_LONG) nbytes += dbr_grLong_size; - if(options & DBR_GR_DOUBLE) nbytes += dbr_grDouble_size; - if(options & DBR_CTRL_LONG) nbytes += dbr_ctrlLong_size; - if(options & DBR_CTRL_DOUBLE)nbytes += dbr_ctrlDouble_size; - if(options & DBR_AL_LONG) nbytes += dbr_alLong_size; - if(options & DBR_AL_DOUBLE) nbytes += dbr_alDouble_size; + if (options & DBR_STATUS) nbytes += dbr_status_size; + if (options & DBR_UNITS) nbytes += dbr_units_size; + if (options & DBR_PRECISION) nbytes += dbr_precision_size; + if (options & DBR_TIME) nbytes += dbr_time_size; + if (options & DBR_ENUM_STRS) nbytes += dbr_enumStrs_size; + if (options & DBR_GR_LONG) nbytes += dbr_grLong_size; + if (options & DBR_GR_DOUBLE) nbytes += dbr_grDouble_size; + if (options & DBR_CTRL_LONG) nbytes += dbr_ctrlLong_size; + if (options & DBR_CTRL_DOUBLE) nbytes += dbr_ctrlDouble_size; + if (options & DBR_AL_LONG) nbytes += dbr_alLong_size; + if (options & DBR_AL_DOUBLE) nbytes += dbr_alDouble_size; return(nbytes); } int epicsShareAPI dbLoadDatabase(const char *file, const char *path, const char *subs) @@ -1016,8 +1034,10 @@ long epicsShareAPI dbGet(DBADDR *paddr, short dbrType, } /* check for array */ - prset = dbGetRset(paddr); - if (no_elements > 1 && prset && prset->get_array_info) { + if (paddr->special == SPC_DBADDR && + no_elements > 1 && + (prset = dbGetRset(paddr)) && + prset->get_array_info) { status = prset->get_array_info(paddr, &no_elements, &offset); } else offset = 0; @@ -1393,7 +1413,8 @@ long epicsShareAPI dbPut(DBADDR *paddr, short dbrType, } else { struct rset *prset = dbGetRset(paddr); - if (prset && prset->get_array_info) { + if (paddr->special == SPC_DBADDR && + prset && prset->get_array_info) { long dummy; status = prset->get_array_info(paddr, &dummy, &offset); @@ -1405,7 +1426,9 @@ long epicsShareAPI dbPut(DBADDR *paddr, short dbrType, nRequest, no_elements, offset); /* update array info */ - if (prset && prset->put_array_info && !status) { + if (!status && + paddr->special == SPC_DBADDR && + prset && prset->put_array_info) { status = prset->put_array_info(paddr, nRequest); } } diff --git a/src/dbStatic/dbStaticLib.c b/src/dbStatic/dbStaticLib.c index 4d1fa911a..b9063e520 100644 --- a/src/dbStatic/dbStaticLib.c +++ b/src/dbStatic/dbStaticLib.c @@ -46,7 +46,6 @@ int dbStaticDebug = 0; static char *pNullString = ""; #define messagesize 100 #define RPCL_LEN 184 -#define MAX_FIELD_NAME_LENGTH 20 static char *ppstring[5]={"NPP","PP","CA","CP","CPP"}; static char *msstring[2]={"NMS","MS"}; @@ -299,24 +298,19 @@ done: static long putParmString(char **pparm,const char *pstring) { - size_t size; - - if(*pparm && (*pparm != pNullString)){ - free((void *)(*pparm)); - *pparm = pNullString; + if (*pparm && *pparm != pNullString) { + free(*pparm); + *pparm = pNullString; } - if(!pstring) return(0); - if(!(pstring = strchr(pstring,'@'))) return(0); - pstring++; - size = strlen(pstring) + 1; - if(size==1) return(0); - *pparm = dbCalloc(size, sizeof(char *)); - strcpy(*pparm,pstring); - return(0); + if (!pstring) return 0; + pstring = strchr(pstring, '@'); + if (!pstring || !*++pstring) return 0; + *pparm = epicsStrDup(pstring); + return 0; } void dbFreeLinkContents(struct link *plink) -{ +{ char *parm = NULL; switch(plink->type) { @@ -331,7 +325,7 @@ void dbFreeLinkContents(struct link *plink) case INST_IO: parm = plink->value.instio.string; break; case BBGPIB_IO: parm = plink->value.bbgpibio.parm;break; case VXI_IO: parm = plink->value.vxiio.parm; break; - default: + default: epicsPrintf("dbFreeLink called but link type unknown\n"); } if(parm && (parm != pNullString)) free((void *)parm); @@ -1358,25 +1352,33 @@ long epicsShareAPI dbPutRecordAttribute( return(0); } -long epicsShareAPI dbGetRecordAttribute(DBENTRY *pdbentry,const char *name) +long dbGetAttributePart(DBENTRY *pdbentry, const char **ppname) { - dbRecordType *precordType = pdbentry->precordType; - int compare; + dbRecordType *precordType = pdbentry->precordType; + const char *pname = *ppname; dbRecordAttribute *pattribute; - if(!precordType) return(S_dbLib_recordTypeNotFound); + if (!precordType) return S_dbLib_recordTypeNotFound; pattribute = (dbRecordAttribute *)ellFirst(&precordType->attributeList); - while(pattribute) { - compare = strcmp(pattribute->name,name); - if(compare==0) { - pdbentry->pflddes = pattribute->pdbFldDes; - pdbentry->pfield = pattribute->value; - return(0); - } - if(compare>=0) break; - pattribute = (dbRecordAttribute *)ellNext(&pattribute->node); + while (pattribute) { + int nameLen = strlen(pattribute->name); + int compare = strncmp(pattribute->name, pname, nameLen); + int ch = pname[nameLen]; + if (compare == 0 && !(ch == '_' || isalnum(ch))) { + pdbentry->pflddes = pattribute->pdbFldDes; + pdbentry->pfield = pattribute->value; + *ppname = &pname[nameLen]; + return 0; + } + if (compare >= 0) break; + pattribute = (dbRecordAttribute *)ellNext(&pattribute->node); } - return(S_dbLib_fieldNotFound); + return S_dbLib_fieldNotFound; +} + +long dbGetRecordAttribute(DBENTRY *pdbentry, const char *pname) +{ + return dbGetAttributePart(pdbentry, &pname); } long epicsShareAPI dbFirstField(DBENTRY *pdbentry,int dctonly) @@ -1614,27 +1616,39 @@ long epicsShareAPI dbFreeRecords(DBBASE *pdbbase) return(0); } -long epicsShareAPI dbFindRecord(DBENTRY *pdbentry, const char *name) +long epicsShareAPI dbFindRecordPart(DBENTRY *pdbentry, const char **ppname) { dbBase *pdbbase = pdbentry->pdbbase; - const char *field; + const char *pname = *ppname; + const char *pfn; int lenName; PVDENTRY *ppvdNode; zeroDbentry(pdbentry); - field = strchr(name, '.'); - if (field) { - lenName = field++ - name; + pfn = strchr(pname, '.'); + if (pfn) { + lenName = pfn - pname; } else { - lenName = strlen(name); + lenName = strlen(pname); } - ppvdNode = dbPvdFind(pdbbase, name, lenName); + + ppvdNode = dbPvdFind(pdbbase, pname, lenName); if (!ppvdNode) return S_dbLib_recNotFound; + pdbentry->precnode = ppvdNode->precnode; pdbentry->precordType = ppvdNode->precordType; - if (field) - return dbFindField(pdbentry, field); + *ppname = pname + lenName; + return 0; +} + +long epicsShareAPI dbFindRecord(DBENTRY *pdbentry, const char *pname) +{ + long status = dbFindRecordPart(pdbentry, &pname); + + if (status) return status; + if (*pname == '.') + return dbFindField(pdbentry, ++pname); return 0; } @@ -1867,64 +1881,86 @@ long epicsShareAPI dbCopyRecord(DBENTRY *pdbentry,const char *newRecordName,int return(dbFindRecord(pdbentry,newRecordName)); } -long epicsShareAPI dbFindField(DBENTRY *pdbentry,const char *pname) +long epicsShareAPI dbFindFieldPart(DBENTRY *pdbentry,const char **ppname) { - dbRecordType *precordType = pdbentry->precordType; - dbRecordNode *precnode = pdbentry->precnode; - char *precord; - dbFldDes *pflddes; - short top, bottom, test; - char **papsortFldName; - short *sortFldInd; - int compare,ind; - char fieldName[MAX_FIELD_NAME_LENGTH+1]; - char *pfieldName; + dbRecordType *precordType = pdbentry->precordType; + dbRecordNode *precnode = pdbentry->precnode; + const char *pname = *ppname; + char *precord; + short top, bottom, test; + char **papsortFldName; + short *sortFldInd; + int ch; + int nameLen; - if(!precordType) return(S_dbLib_recordTypeNotFound); - if(!precnode) return(S_dbLib_recNotFound); + if (!precordType) return S_dbLib_recordTypeNotFound; + if (!precnode) return S_dbLib_recNotFound; precord = precnode->precord; papsortFldName = precordType->papsortFldName; sortFldInd = precordType->sortFldInd; - /*copy field name. Stop at null or blank or tab*/ - pfieldName = &fieldName[0]; - for(ind=0; indpvalFldDes)) - return(S_dbLib_recordTypeNotFound); - pdbentry->pflddes = pflddes; - pdbentry->indfield = precordType->indvalFlddes; - return(dbGetFieldAddress(pdbentry)); + + /* Handle absent field name */ + if (nameLen == 0) { + dbFldDes *pflddes = precordType->pvalFldDes; + + if (!pflddes) + return S_dbLib_recordTypeNotFound; + pdbentry->pflddes = pflddes; + pdbentry->indfield = precordType->indvalFlddes; + *ppname = &pname[nameLen]; + return dbGetFieldAddress(pdbentry); } + /* binary search through ordered field names */ top = precordType->no_fields - 1; bottom = 0; test = (top + bottom) / 2; while (1) { - /* check the field name */ - compare = strcmp(papsortFldName[test],pfieldName); - if (compare == 0) { - if(!(pflddes=precordType->papFldDes[sortFldInd[test]])) - return(S_dbLib_recordTypeNotFound); - pdbentry->pflddes = pflddes; - pdbentry->indfield = sortFldInd[test]; - return(dbGetFieldAddress(pdbentry)); - } else if (compare > 0) { - top = test - 1; - if (top < bottom) break; - test = (top + bottom) / 2; - } else { - bottom = test + 1; - if (top < bottom) break; - test = (top + bottom) / 2; - } + int compare = strncmp(papsortFldName[test], pname, nameLen); + if (compare == 0) + compare = strlen(papsortFldName[test]) - nameLen; + if (compare == 0) { + dbFldDes *pflddes = precordType->papFldDes[sortFldInd[test]]; + + if (!pflddes) + return S_dbLib_recordTypeNotFound; + pdbentry->pflddes = pflddes; + pdbentry->indfield = sortFldInd[test]; + *ppname = &pname[nameLen]; + return dbGetFieldAddress(pdbentry); + } else if (compare > 0) { + top = test - 1; + if (top < bottom) break; + test = (top + bottom) / 2; + } else { + bottom = test + 1; + if (top < bottom) break; + test = (top + bottom) / 2; + } } - return(dbGetRecordAttribute(pdbentry,pfieldName)); + return S_dbLib_fieldNotFound; +} + +long epicsShareAPI dbFindField(DBENTRY *pdbentry,const char *pname) +{ + long status = dbFindFieldPart(pdbentry, &pname); + int ch; + + if (status == S_dbLib_fieldNotFound) + return dbGetRecordAttribute(pdbentry, pname); + if (status) return status; + + ch = *pname; + if (ch == 0 || isspace(ch)) return 0; + return S_dbLib_recNotFound; } int epicsShareAPI dbFoundField(DBENTRY *pdbentry) diff --git a/src/dbStatic/dbStaticLib.h b/src/dbStatic/dbStaticLib.h index 225ecfb29..4a676dce3 100644 --- a/src/dbStatic/dbStaticLib.h +++ b/src/dbStatic/dbStaticLib.h @@ -111,10 +111,12 @@ epicsShareFunc long epicsShareAPI dbFirstRecordType(DBENTRY *pdbentry); epicsShareFunc long epicsShareAPI dbNextRecordType(DBENTRY *pdbentry); epicsShareFunc char * epicsShareAPI dbGetRecordTypeName(DBENTRY *pdbentry); epicsShareFunc int epicsShareAPI dbGetNRecordTypes(DBENTRY *pdbentry); -epicsShareFunc long epicsShareAPI dbPutRecordAttribute( - DBENTRY *pdbentry,const char *name,const char*value); -epicsShareFunc long epicsShareAPI dbGetRecordAttribute( - DBENTRY *pdbentry,const char *name); +epicsShareFunc long epicsShareAPI dbPutRecordAttribute(DBENTRY *pdbentry, + const char *name, const char*value); +epicsShareFunc long epicsShareAPI dbGetRecordAttribute(DBENTRY *pdbentry, + const char *name); +epicsShareFunc long epicsShareAPI dbGetAttributePart(DBENTRY *pdbentry, + const char **ppname); epicsShareFunc long epicsShareAPI dbFirstField(DBENTRY *pdbentry,int dctonly); epicsShareFunc long epicsShareAPI dbNextField(DBENTRY *pdbentry,int dctonly); @@ -125,46 +127,51 @@ epicsShareFunc char * epicsShareAPI dbGetDefault(DBENTRY *pdbentry); epicsShareFunc char * epicsShareAPI dbGetPrompt(DBENTRY *pdbentry); epicsShareFunc int epicsShareAPI dbGetPromptGroup(DBENTRY *pdbentry); -epicsShareFunc long epicsShareAPI dbCreateRecord( - DBENTRY *pdbentry,const char *precordName); +epicsShareFunc long epicsShareAPI dbCreateRecord(DBENTRY *pdbentry, + const char *pname); epicsShareFunc long epicsShareAPI dbDeleteRecord(DBENTRY *pdbentry); epicsShareFunc long epicsShareAPI dbFreeRecords(DBBASE *pdbbase); -epicsShareFunc long epicsShareAPI dbFindRecord( - DBENTRY *pdbentry,const char *precordName); -epicsShareFunc long epicsShareAPI dbFirstRecord( - DBENTRY *pdbentry); /*first of record type*/ +epicsShareFunc long epicsShareAPI dbFindRecordPart(DBENTRY *pdbentry, + const char **ppname); +epicsShareFunc long epicsShareAPI dbFindRecord(DBENTRY *pdbentry, + const char *pname); + +epicsShareFunc long epicsShareAPI dbFirstRecord(DBENTRY *pdbentry); epicsShareFunc long epicsShareAPI dbNextRecord(DBENTRY *pdbentry); epicsShareFunc int epicsShareAPI dbGetNRecords(DBENTRY *pdbentry); epicsShareFunc int epicsShareAPI dbGetNAliases(DBENTRY *pdbentry); epicsShareFunc char * epicsShareAPI dbGetRecordName(DBENTRY *pdbentry); -epicsShareFunc long epicsShareAPI dbRenameRecord( - DBENTRY *pdbentry,const char *newName); -epicsShareFunc long epicsShareAPI dbCopyRecord( - DBENTRY *pdbentry,const char *newRecordName,int overWriteOK); +epicsShareFunc long epicsShareAPI dbRenameRecord(DBENTRY *pdbentry, + const char *newName); +epicsShareFunc long epicsShareAPI dbCopyRecord(DBENTRY *pdbentry, + const char *newRecordName, int overWriteOK); epicsShareFunc long epicsShareAPI dbVisibleRecord(DBENTRY *pdbentry); epicsShareFunc long epicsShareAPI dbInvisibleRecord(DBENTRY *pdbentry); epicsShareFunc int epicsShareAPI dbIsVisibleRecord(DBENTRY *pdbentry); -epicsShareFunc long epicsShareAPI dbCreateAlias( - DBENTRY *pdbentry, const char *paliasName); +epicsShareFunc long epicsShareAPI dbCreateAlias(DBENTRY *pdbentry, + const char *paliasName); epicsShareFunc int epicsShareAPI dbIsAlias(DBENTRY *pdbentry); epicsShareFunc long epicsShareAPI dbDeleteAliases(DBENTRY *pdbentry); -epicsShareFunc long epicsShareAPI dbFindField( - DBENTRY *pdbentry,const char *pfieldName); +epicsShareFunc long epicsShareAPI dbFindFieldPart(DBENTRY *pdbentry, + const char **ppname); +epicsShareFunc long epicsShareAPI dbFindField(DBENTRY *pdbentry, + const char *pfieldName); epicsShareFunc int epicsShareAPI dbFoundField(DBENTRY *pdbentry); epicsShareFunc char * epicsShareAPI dbGetString(DBENTRY *pdbentry); -epicsShareFunc long epicsShareAPI dbPutString( - DBENTRY *pdbentry,const char *pstring); -epicsShareFunc char * epicsShareAPI dbVerify( - DBENTRY *pdbentry,const char *pstring); +epicsShareFunc long epicsShareAPI dbPutString(DBENTRY *pdbentry, + const char *pstring); +epicsShareFunc char * epicsShareAPI dbVerify(DBENTRY *pdbentry, + const 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 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);