Merged Michael's link-parsing branch

This commit is contained in:
Andrew Johnson
2015-02-03 00:38:23 -06:00
9 changed files with 602 additions and 533 deletions
+46 -19
View File
@@ -55,6 +55,7 @@
#include "dbScan.h"
#include "dbServer.h"
#include "dbStaticLib.h"
#include "dbStaticPvt.h"
#include "devSup.h"
#include "epicsEvent.h"
#include "link.h"
@@ -935,15 +936,17 @@ devSup* dbDSETtoDevSup(dbRecordType *prdes, struct dset *pdset) {
static long dbPutFieldLink(DBADDR *paddr,
short dbrType, const void *pbuffer, long nRequest)
{
dbLinkInfo link_info;
DBADDR *pdbaddr = NULL;
dbCommon *precord = paddr->precord;
dbFldDes *pfldDes = paddr->pfldDes;
long special = paddr->special;
struct link *plink = (struct link *)paddr->pfield;
const char *pstring = (const char *)pbuffer;
DBENTRY dbEntry;
struct dsxt *old_dsxt = NULL;
struct dset *new_dset = NULL;
struct dsxt *new_dsxt = NULL;
devSup *new_devsup = NULL;
long status;
int isDevLink;
short scan;
@@ -962,31 +965,55 @@ static long dbPutFieldLink(DBADDR *paddr,
return S_db_badDbrtype;
}
dbInitEntry(pdbbase, &dbEntry);
status = dbFindRecord(&dbEntry, precord->name);
if (!status) status = dbFindField(&dbEntry, pfldDes->name);
if (status) goto finish;
status = dbParseLink(pstring, pfldDes->field_type, &link_info);
if (status)
return status;
if (link_info.ltype == PV_LINK &&
(link_info.modifiers & (pvlOptCA | pvlOptCP | pvlOptCPP)) == 0) {
DBADDR tempaddr;
if (dbNameToAddr(link_info.target, &tempaddr)==0) {
/* This will become a DB link. */
pdbaddr = malloc(sizeof(*pdbaddr));
if (!pdbaddr) {
status = S_db_noMemory;
goto cleanup;
}
*pdbaddr = tempaddr; /* struct copy */
}
}
isDevLink = ellCount(&precord->rdes->devList) > 0 &&
(strcmp(pfldDes->name, "INP") == 0 ||
strcmp(pfldDes->name, "OUT") == 0);
pfldDes->isDevLink;
dbLockSetGblLock();
dbLockSetRecordLock(precord);
if (pdbaddr)
dbLockSetRecordLock(pdbaddr->precord);
scan = precord->scan;
if (isDevLink) {
devSup *pdevSup = dbDTYPtoDevSup(precord->rdes, precord->dtyp);
if (pdevSup) {
new_dset = pdevSup->pdset;
new_dsxt = pdevSup->pdsxt;
new_devsup = dbDTYPtoDevSup(precord->rdes, precord->dtyp);
if (new_devsup) {
new_dset = new_devsup->pdset;
new_dsxt = new_devsup->pdsxt;
}
}
if (dbCanSetLink(plink, &link_info, new_devsup)) {
/* link type mis-match prevents assignment */
status = S_dbLib_badField;
goto unlock;
}
if (isDevLink) {
if (precord->dset) {
pdevSup = dbDSETtoDevSup(precord->rdes, precord->dset);
if (pdevSup)
old_dsxt = pdevSup->pdsxt;
devSup *old_devsup = dbDSETtoDevSup(precord->rdes, precord->dset);
if (old_devsup)
old_dsxt = old_devsup->pdsxt;
}
if (new_dsxt == NULL ||
@@ -1012,7 +1039,7 @@ static long dbPutFieldLink(DBADDR *paddr,
switch (plink->type) { /* Old link type */
case DB_LINK:
case CA_LINK:
dbRemoveLink(plink);
dbRemoveLink(plink);
break;
case PV_LINK:
@@ -1032,7 +1059,7 @@ static long dbPutFieldLink(DBADDR *paddr,
if (special) status = dbPutSpecial(paddr, 0);
if (!status) status = dbPutString(&dbEntry, pstring);
if (!status) status = dbSetLink(plink, &link_info, new_devsup);
if (!status && special) status = dbPutSpecial(paddr, 1);
@@ -1059,7 +1086,7 @@ static long dbPutFieldLink(DBADDR *paddr,
switch (plink->type) { /* New link type */
case PV_LINK:
dbAddLink(precord, plink, pfldDes->field_type);
dbAddLink(precord, plink, pfldDes->field_type, pdbaddr);
break;
case CONSTANT:
@@ -1090,8 +1117,8 @@ postScanEvent:
db_post_events(precord, &precord->scan, DBE_VALUE | DBE_LOG);
unlock:
dbLockSetGblUnlock();
finish:
dbFinishEntry(&dbEntry);
cleanup:
free(link_info.target);
return status;
}
+12 -26
View File
@@ -144,26 +144,6 @@ static long dbDbInitLink(struct link *plink, short dbfType)
return 0;
}
static long dbDbAddLink(struct link *plink, short dbfType)
{
DBADDR dbaddr;
long status;
DBADDR *pdbAddr;
status = dbNameToAddr(plink->value.pv_link.pvname, &dbaddr);
if (status)
return status;
plink->type = DB_LINK;
pdbAddr = dbCalloc(1, sizeof(struct dbAddr));
*pdbAddr = dbaddr; /* structure copy */
plink->value.pv_link.pvt = pdbAddr;
dbLockSetRecordLock(pdbAddr->precord);
dbLockSetMerge(plink->value.pv_link.precord, pdbAddr->precord);
return 0;
}
static void dbDbRemoveLink(struct link *plink)
{
free(plink->value.pv_link.pvt);
@@ -400,7 +380,7 @@ static void dbDbScanFwdLink(struct link *plink)
dbScanPassive(precord, paddr->precord);
}
lset dbDb_lset = { dbDbInitLink, dbDbAddLink, NULL, dbDbRemoveLink,
lset dbDb_lset = { dbDbRemoveLink,
dbDbIsLinkConnected, dbDbGetDBFtype, dbDbGetElements, dbDbGetValue,
dbDbGetControlLimits, dbDbGetGraphicLimits, dbDbGetAlarmLimits,
dbDbGetPrecision, dbDbGetUnits, dbDbGetAlarm, dbDbGetTimeStamp,
@@ -442,17 +422,23 @@ void dbInitLink(struct dbCommon *precord, struct link *plink, short dbfType)
}
}
void dbAddLink(struct dbCommon *precord, struct link *plink, short dbfType)
void dbAddLink(struct dbCommon *precord, struct link *plink, short dbfType, DBADDR *ptargetaddr)
{
plink->value.pv_link.precord = precord;
if (plink == &precord->tsel)
recGblTSELwasModified(plink);
if (!(plink->value.pv_link.pvlMask & (pvlOptCA | pvlOptCP | pvlOptCPP))) {
/* Can we make it a DB link? */
if (!dbDbAddLink(plink, dbfType))
return;
if (ptargetaddr) {
/* make a DB link */
plink->type = DB_LINK;
plink->value.pv_link.pvt = ptargetaddr;
/* target record is already locked in dbPutFieldLink() */
dbLockSetMerge(plink->value.pv_link.precord, ptargetaddr->precord);
return;
}
/* Make it a CA link */
+2 -4
View File
@@ -20,15 +20,13 @@
#include "shareLib.h"
#include "epicsTypes.h"
#include "epicsTime.h"
#include "dbAddr.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct lset {
long (*initLink)(struct link *plink, short dbfType);
long (*addLink)(struct link *plink, short dbfType);
long (*loadLink)(struct link *plink, short dbrType, void *pbuffer);
void (*removeLink)(struct link *plink);
int (*isLinkConnected)(const struct link *plink);
int (*getDBFtype)(const struct link *plink);
@@ -55,7 +53,7 @@ typedef struct lset {
epicsShareFunc void dbInitLink(struct dbCommon *precord, struct link *plink,
short dbfType);
epicsShareFunc void dbAddLink(struct dbCommon *precord, struct link *plink,
short dbfType);
short dbfType, DBADDR *ptargetaddr);
epicsShareFunc long dbLoadLink(struct link *plink, short dbrType,
void *pbuffer);
epicsShareFunc void dbRemoveLink(struct link *plink);
+128 -8
View File
@@ -20,6 +20,7 @@
#include "dbAccess.h"
#include "registry.h"
#include "dbStaticLib.h"
#include "dbStaticPvt.h"
#include "osiFileName.h"
#include "dbmf.h"
#include "errlog.h"
@@ -28,8 +29,125 @@
#include "testMain.h"
static
int testStrcmp(int expect, const char *A, const char *B) {
static const char op[] = "<=>";
int ret = strcmp(A,B);
testOk(ret==expect, "\"%s\" %c= \"%s\"",
A, op[expect+1], B);
return ret==expect;
}
void dbTestIoc_registerRecordDeviceDriver(struct dbBase *);
#define TEST_CONSTANT(SET, EXPECT) {SET, {CONSTANT, EXPECT}}
#define TEST_PV_LINK(SET, PV, MOD) {SET, {PV_LINK, PV, MOD}}
#define TEST_HW(SET, TYPE, ID, PARM, ...) {SET, {TYPE, PARM, 0, ID, {__VA_ARGS__}}}
static const struct testParseDataT {
const char * const str;
dbLinkInfo info;
} testParseData[] = {
TEST_CONSTANT("", ""),
TEST_CONSTANT("0.1", "0.1"),
TEST_CONSTANT(" 0.2\t ", "0.2"),
TEST_PV_LINK("0.1a", "0.1a", 0),
TEST_PV_LINK(" hello ", "hello", 0),
TEST_PV_LINK(" hellox MSI", "hellox", pvlOptMSI),
TEST_PV_LINK(" world MSICP", "world", pvlOptMSI|pvlOptCP),
TEST_HW("#C14 S145 @testing", VME_IO, "CS", "testing", 14, 145),
TEST_HW("#B11 C12 N13 A14 F15 @cparam", CAMAC_IO, "BCNAF", "cparam", 11, 12, 13, 14, 15),
TEST_HW(" #B111 C112 N113 @cparam", CAMAC_IO, "BCN", "cparam", 111, 112, 113),
TEST_HW(" @hello world ", INST_IO, "", "hello world"),
{NULL}
};
static void testLinkParse(void)
{
const struct testParseDataT *td = testParseData;
dbLinkInfo info;
testDiag("link parsing");
testdbPrepare();
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
dbTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("dbPutLinkTest.db", NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
for(;td->str; td++) {
int i, N;
testDiag("Parse \"%s\"", td->str);
testOk1(dbParseLink(td->str, DBF_INLINK, &info)==0);
testOk1(info.ltype==td->info.ltype);
if(td->info.target)
testStrcmp(0, info.target, td->info.target);
if(info.ltype==td->info.ltype) {
switch(info.ltype) {
case PV_LINK:
testOk1(info.modifiers==td->info.modifiers);
break;
case VME_IO:
testStrcmp(0, info.hwid, td->info.hwid);
N = strlen(td->info.hwid);
for(i=0; i<N; i++)
testOk(info.hwnums[i]==td->info.hwnums[i], "%d == %d",
info.hwnums[i], td->info.hwnums[i]);
}
}
free(info.target);
}
testIocShutdownOk();
testdbCleanup();
}
static const char *testParseFailData[] = {
"#",
"#S",
"#ABC",
"#A0 B",
"#A0 B @",
"#A0 B C @",
"#R1 M2 D3 E4 @oops", /* RF_IO has no parm */
"#C1 S2", /* VME_IO needs parm */
NULL
};
static void testLinkFailParse(void)
{
const char * const *td = testParseFailData;
dbLinkInfo info;
testDiag("link parsing of invalid input");
testdbPrepare();
testdbReadDatabase("dbTestIoc.dbd", NULL, NULL);
dbTestIoc_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("dbPutLinkTest.db", NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
for(;*td; td++) {
testDiag("Expect failure \"%s\"", *td);
testOk1(dbParseLink(*td, DBF_INLINK, &info)==S_dbLib_badField);
}
testIocShutdownOk();
testdbCleanup();
}
static const struct testDataT {
const char * const linkstring;
short linkType;
@@ -39,6 +157,7 @@ static const struct testDataT {
{"", CONSTANT, 0},
{"0", CONSTANT, 0},
{"42", CONSTANT, 0},
{"0x1", CONSTANT, 0},
{"x1", DB_LINK, 0, "x1 NPP NMS"},
{"x1.VAL", DB_LINK, 0, "x1.VAL NPP NMS"},
@@ -77,17 +196,17 @@ static void testCADBSet(void)
prec = (xRecord*)testdbRecordPtr("x1");
plink = &prec->lnk;
for(;td->linkstring;td++) {
for (;td->linkstring;td++) {
testDiag("x1.LNK <- \"%s\"", td->linkstring);
testdbPutFieldOk("x1.LNK", DBF_STRING, td->linkstring);
if(td->linkback)
if (td->linkback)
testdbGetFieldEqual("x1.LNK", DBF_STRING, td->linkback);
else
testdbGetFieldEqual("x1.LNK", DBF_STRING, td->linkstring);
testOk1(plink->type==td->linkType);
if(plink->type==td->linkType) {
if (plink->type==td->linkType) {
switch(td->linkType) {
case CONSTANT:
if(plink->value.constantStr)
@@ -327,7 +446,7 @@ static void testLinkInitFail(void)
testOk1(plink->type==VME_IO);
testOk1(plink->value.vmeio.parm!=NULL);
testdbGetFieldEqual("eVME_IO2.INP", DBR_STRING, "#C200 S0 @");
testdbGetFieldEqual("eVME_IO2.INP", DBR_STRING, "#C0 S0 @");
prec = (xRecord*)testdbRecordPtr("eVME_IO2");
plink = &prec->inp;
@@ -364,9 +483,8 @@ static void testLinkFail(void)
/* INST_IO doesn't accept empty string */
testdbPutFieldFail(S_dbLib_badField, "rINST_IO.INP", DBR_STRING, "");
/* INST_IO accepts invalid input as empty string */
testdbPutFieldOk("rINST_IO.INP", DBR_STRING, "abc");
testdbGetFieldEqual("rINST_IO.INP", DBR_STRING, "@");
/* INST_IO doesn't accept empty string */
testdbPutFieldFail(S_dbLib_badField, "rINST_IO.INP", DBR_STRING, "abc");
/* syntax errors */
testdbPutFieldFail(S_dbLib_badField, "rVME_IO.INP", DBR_STRING, "#S201 C200 @another VME_IO");
@@ -387,7 +505,9 @@ static void testLinkFail(void)
MAIN(dbPutLinkTest)
{
testPlan(200);
testPlan(251);
testLinkParse();
testLinkFailParse();
testCADBSet();
testHWInitSet();
testHWMod();
+3 -2
View File
@@ -76,8 +76,9 @@ typedef struct dbFldDes{ /* field description */
short indRecordType; /*within dbRecordType.papFldDes */
short special; /*Special processing requirements */
dbfType field_type; /*Field type as defined in dbFldTypes.h */
unsigned int process_passive:1;/*should dbPutField process passive */
unsigned int prop:1;/*field is a metadata, post DBE_PROPERTY on change*/
unsigned int process_passive:1;/*should dbPutField process passive */
unsigned int prop:1;/*field is a metadata, post DBE_PROPERTY on change*/
unsigned int isDevLink:1; /* true for INP/OUT fields */
ctType base; /*base for integer to string conversions*/
short promptgroup; /*prompt, i.e. gui group */
short interest; /*interest level */
+2
View File
@@ -486,6 +486,8 @@ static void dbRecordtypeFieldHead(char *name,char *type)
allocTemp(pdbFldDes);
pdbFldDes->name = epicsStrDup(name);
pdbFldDes->as_level = ASL1;
pdbFldDes->isDevLink = strcmp(pdbFldDes->name, "INP")==0 ||
strcmp(pdbFldDes->name, "OUT")==0;
for(i=0; i<DBF_NTYPES; i++) {
if(strcmp(type,pamapdbfType[i].strvalue)==0) {
pdbFldDes->field_type = pamapdbfType[i].value;
+361 -465
View File
@@ -45,6 +45,8 @@
#include "link.h"
#include "special.h"
#include "dbCommon.h"
int dbStaticDebug = 0;
static char *pNullString = "";
#define messagesize 100
@@ -85,12 +87,9 @@ static int mapDBFtoDCT[DBF_NOACCESS+1] = {
/*forward references for private routines*/
static FILE *openOutstream(const char *filename);
static void finishOutstream(FILE *stream);
static long setLinkType(DBENTRY *pdbentry);
static long putParmString(char **pparm,const char *pstring);
static void entryErrMessage(DBENTRY *pdbentry,long status,char *mess);
static void zeroDbentry(DBENTRY *pdbentry);
static char *getpMessage(DBENTRY *pdbentry);
static long putPvLink(DBENTRY *pdbentry,short pvlMask,const char *pvname);
static long dbAddOnePath (DBBASE *pdbbase, const char *path, unsigned length);
/* internal routines*/
@@ -115,103 +114,6 @@ static void finishOutstream(FILE *stream)
}
}
static long setLinkType(DBENTRY *pdbentry)
{
DBENTRY dbEntry;
dbRecordType *precordType;
devSup *pdevSup;
DBLINK *plink;
long status=0;
int link_type,ind,type;
dbCopyEntryContents(pdbentry, &dbEntry);
status = dbFindField(&dbEntry, "DTYP");
if (status) {
epicsPrintf("field DTYP does not exist for recordtype %s\n",
dbGetRecordTypeName(&dbEntry));
status = S_dbLib_fieldNotFound;
goto done;
}
precordType = dbEntry.precordType;
if (!precordType) {
status = S_dbLib_badField;
goto done;
}
if (ellCount(&precordType->devList) == 0) goto done;
ind = dbGetMenuIndex(&dbEntry);
if (ind == -1) {
char *pstring;
pstring = dbGetString(&dbEntry);
if (strstr(pstring, "$(") || strstr(pstring, "${")) {
link_type = MACRO_LINK;
} else {
status = S_dbLib_badField;
goto done;
}
} else {
pdevSup = (devSup *)ellNth(&precordType->devList, ind + 1);
if (!pdevSup) {
status = S_dbLib_badField;
goto done;
}
link_type = pdevSup->link_type;
}
plink = (DBLINK *)pdbentry->pfield;
if (plink->type == link_type) goto done;
if (plink->text)
{
/* re-parse link text when DTYP has changed */
char * link_text;
link_text = plink->text;
plink->text = NULL;
dbFreeLinkContents(plink);
plink->type = link_type;
dbPutString(pdbentry, link_text);
free(link_text);
goto done;
}
type = plink->type;
if ((type == CONSTANT || type == PV_LINK ||
type == PN_LINK || type == DB_LINK || type == CA_LINK) &&
(link_type == CONSTANT || link_type == PV_LINK)) goto done;
dbFreeLinkContents(plink);
plink->type = link_type;
switch (plink->type) {
case VME_IO: plink->value.vmeio.parm = pNullString; break;
case CAMAC_IO: plink->value.camacio.parm = pNullString; break;
case AB_IO: plink->value.abio.parm = pNullString; break;
case GPIB_IO: plink->value.gpibio.parm = pNullString; break;
case BITBUS_IO: plink->value.bitbusio.parm = pNullString; break;
case INST_IO: plink->value.instio.string = pNullString; break;
case BBGPIB_IO: plink->value.bbgpibio.parm = pNullString; break;
case VXI_IO: plink->value.vxiio.parm = pNullString; break;
}
done:
dbFinishEntry(&dbEntry);
return(status);
}
static long putParmString(char **pparm,const char *pstring)
{
if (*pparm && *pparm != pNullString) {
free(*pparm);
*pparm = pNullString;
}
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;
@@ -309,35 +211,6 @@ static char *getpMessage(DBENTRY *pdbentry)
return msg;
}
static long putPvLink(DBENTRY *pdbentry,short pvlMask,const char *pvname)
{
dbFldDes *pflddes;
DBLINK *plink;
char *pname;
dbGetFieldAddress(pdbentry);
pflddes = pdbentry->pflddes;
if(!pflddes) return(-1);
plink = (DBLINK *)pdbentry->pfield;
if(!plink) return(-1);
switch (pflddes->field_type) {
case DBF_INLINK:
case DBF_OUTLINK:
case DBF_FWDLINK:
if(plink->type != PV_LINK) return(S_dbLib_badLink);
pname = plink->value.pv_link.pvname;
if(pname) free((void *)pname);
pname = dbCalloc(strlen(pvname)+1,sizeof(char));
plink->value.pv_link.pvname = pname;
strcpy(pname,pvname);
plink->value.pv_link.pvlMask = pvlMask;
return(0);
default:
errPrintf(-1,__FILE__, __LINE__,"Logic Error\n");
}
return(S_dbLib_badLink);
}
/*Public only for dbStaticNoRun*/
dbDeviceMenu *dbGetDeviceMenu(DBENTRY *pdbentry)
{
@@ -2017,13 +1890,348 @@ char * dbGetString(DBENTRY *pdbentry)
return (message);
}
static void cvtDecimalOrHexToShort(char *from,short *value)
long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec)
{
if(strspn(from,"0x")==2 || strspn(from,"0X")==2) {
sscanf(from,"%hi",value);
} else {
sscanf(from,"%hd",value);
short i;
for (i=0; i<rtyp->no_links; i++) {
dbLinkInfo link_info;
dbFldDes *pflddes = rtyp->papFldDes[rtyp->link_ind[i]];
DBLINK *plink = (DBLINK *)(((char *)prec) + pflddes->offset);
devSup *devsup = NULL;
/* link fields are zero'd on allocation.
* so are effectively CONSTANT, but with constantStr==NULL.
* Here we initialize them to have the correct link type,
* with zero values and empty (but non-NULL) strings.
*/
if(pflddes->isDevLink) {
devsup = (devSup *)ellNth(&rtyp->devList, prec->dtyp+1);
}
if(devsup)
plink->type = devsup->link_type;
else
plink->type = CONSTANT;
switch (plink->type) {
case CONSTANT: plink->value.constantStr = callocMustSucceed(1, 1, "init CONSTANT link"); break;
case PV_LINK: plink->value.pv_link.pvname = callocMustSucceed(1, 1, "init PV_LINK"); break;
case VME_IO: plink->value.vmeio.parm = pNullString; break;
case CAMAC_IO: plink->value.camacio.parm = pNullString; break;
case AB_IO: plink->value.abio.parm = pNullString; break;
case GPIB_IO: plink->value.gpibio.parm = pNullString; break;
case BITBUS_IO: plink->value.bitbusio.parm = pNullString; break;
case INST_IO: plink->value.instio.string = pNullString; break;
case BBGPIB_IO: plink->value.bbgpibio.parm = pNullString; break;
case VXI_IO: plink->value.vxiio.parm = pNullString; break;
}
if(!plink->text)
continue;
if(dbParseLink(plink->text, pflddes->field_type, &link_info)!=0) {
/* This was already parsed once when ->text was set.
* Any syntax error messages were printed at that time.
*/
} else if(dbCanSetLink(plink, &link_info, devsup)!=0) {
errlogPrintf("Error: %s.%s: can't initialize link type %d with \"%s\" (type %d)\n",
prec->name, pflddes->name, plink->type, plink->text, link_info.ltype);
} else if(dbSetLink(plink, &link_info, devsup)) {
errlogPrintf("Error: %s.%s: failed to initialize link type %d with \"%s\" (type %d)\n",
prec->name, pflddes->name, plink->type, plink->text, link_info.ltype);
}
free(plink->text);
plink->text = NULL;
}
return 0;
}
long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
{
char *pstr;
size_t len;
double value;
memset(pinfo, 0, sizeof(*pinfo));
/* Strip leading white space */
while (*str && isspace((int)*str)) str++;
len = strlen(str);
/* Strip trailing white space */
while (len > 0 && isspace((int)str[len-1])) len--;
pstr = malloc(len + 1);
if (!pstr)
return S_dbLib_outMem;
pinfo->target = pstr;
/* Check for Instrument I/O links */
if (*str == '@') {
pinfo->ltype = INST_IO;
/* Store everything after the '@' */
memcpy(pstr, str+1, --len);
pstr[len] = '\0';
return 0;
}
/* Store the stripped string */
memcpy(pstr, str, len);
pstr[len] = '\0';
/* Check for other HW link types */
if (*pstr == '#') {
int ret;
char junk = 0;
char *parm = strchr(pstr, '@'); /* find start of parm string */
if (parm) {
*parm++ = '\0'; /* isolate the parm string for later */
len -= (parm - pstr);
}
/* generalized extraction of ID charactor and integer pairs (eg. "#C15 S14") */
ret = sscanf(pinfo->target, "# %c%d %c%d %c%d %c%d %c%d %c",
&pinfo->hwid[0], &pinfo->hwnums[0],
&pinfo->hwid[1], &pinfo->hwnums[1],
&pinfo->hwid[2], &pinfo->hwnums[2],
&pinfo->hwid[3], &pinfo->hwnums[3],
&pinfo->hwid[4], &pinfo->hwnums[4],
&junk);
/* ret<0 when pattern not matched
* ret==11 when extra non-space before '@'.
* ret is odd when a number is missing
*/
if (ret<0 || ret>10 || ret%2==1) goto fail;
if (strcmp(pinfo->hwid, "CS")==0) pinfo->ltype = VME_IO;
else if (strcmp(pinfo->hwid, "BCN")==0) pinfo->ltype = CAMAC_IO;
else if (strcmp(pinfo->hwid, "BCNA")==0) pinfo->ltype = CAMAC_IO;
else if (strcmp(pinfo->hwid, "BCNF")==0) pinfo->ltype = CAMAC_IO;
else if (strcmp(pinfo->hwid, "BCNAF")==0) pinfo->ltype = CAMAC_IO;
else if (strcmp(pinfo->hwid, "RMDE")==0) pinfo->ltype = RF_IO;
else if (strcmp(pinfo->hwid, "LACS")==0) pinfo->ltype = AB_IO;
else if (strcmp(pinfo->hwid, "LA")==0) pinfo->ltype = GPIB_IO;
else if (strcmp(pinfo->hwid, "LNPS")==0) pinfo->ltype = BITBUS_IO;
else if (strcmp(pinfo->hwid, "LBG")==0) pinfo->ltype = BBGPIB_IO;
else if (strcmp(pinfo->hwid, "VCS")==0) pinfo->ltype = VXI_IO;
else if (strcmp(pinfo->hwid, "VS")==0) pinfo->ltype = VXI_IO;
else goto fail;
if (parm && pinfo->ltype != RF_IO) {
/* move parm string to beginning of buffer */
memmove(pinfo->target, parm, len + 1);
} else if (!parm && pinfo->ltype == RF_IO) {
/* RF_IO, the string isn't needed at all */
free(pinfo->target);
pinfo->target = NULL;
} else {
/* missing parm when required, or found parm when not expected */
free(pinfo->target);
pinfo->target = NULL;
return S_dbLib_badField;
}
return 0;
}
/* Link is a constant if empty or it holds just a number */
if (len == 0 || epicsParseDouble(pstr, &value, NULL) == 0) {
pinfo->ltype = CONSTANT;
return 0;
}
pinfo->ltype = PV_LINK;
pstr = strchr(pstr, ' '); /* find start of link modifiers (can't be seperated by tabs) */
if (pstr) {
*pstr++ = '\0'; /* isolate modifiers. pinfo->target is PV name only for re-use in struct pv_link */
/* Space seperation of modifiers isn't required, and other chars are ignored.
* Order of comparisons resolves ambiguity by checking for
* longer matches first.
* eg. "QQCPPXMSITT" is pvlOptCPP|pvlOptMSI
*/
if (strstr(pstr, "NPP")) pinfo->modifiers = 0;
else if (strstr(pstr, "CPP")) pinfo->modifiers = pvlOptCPP;
else if (strstr(pstr, "PP")) pinfo->modifiers = pvlOptPP;
else if (strstr(pstr, "CA")) pinfo->modifiers = pvlOptCA;
else if (strstr(pstr, "CP")) pinfo->modifiers = pvlOptCP;
if (strstr(pstr, "NMS")) pinfo->modifiers |= pvlOptNMS;
else if (strstr(pstr, "MSI")) pinfo->modifiers |= pvlOptMSI;
else if (strstr(pstr, "MSS")) pinfo->modifiers |= pvlOptMSS;
else if (strstr(pstr, "MS")) pinfo->modifiers |= pvlOptMS;
/* filter modifiers based on link type */
switch(ftype) {
case DBF_INLINK: /* accept all */ break;
case DBF_OUTLINK: pinfo->modifiers &= ~pvlOptCPP; break;
case DBF_FWDLINK: pinfo->modifiers &= pvlOptCA; break;
}
}
return 0;
fail:
free(pinfo->target);
return S_dbLib_badField;
}
long dbCanSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup)
{
/* consume allocated string pinfo->target on failure */
int link_type = CONSTANT;
if(devsup)
link_type = devsup->link_type;
if(link_type==pinfo->ltype)
return 0;
switch(pinfo->ltype) {
case CONSTANT:
case PV_LINK:
if(link_type==CONSTANT || link_type==PV_LINK)
return 0;
default:
free(pinfo->target);
pinfo->target = NULL;
return 1;
}
}
static
void dbSetLinkConst(DBLINK *plink, dbLinkInfo *pinfo)
{
plink->type = CONSTANT;
plink->value.constantStr = pinfo->target;
pinfo->target = NULL;
}
static
void dbSetLinkPV(DBLINK *plink, dbLinkInfo *pinfo)
{
plink->type = PV_LINK;
plink->value.pv_link.pvname = pinfo->target;
plink->value.pv_link.pvlMask = pinfo->modifiers;
pinfo->target = NULL;
}
static
void dbSetLinkHW(DBLINK *plink, dbLinkInfo *pinfo)
{
switch(pinfo->ltype) {
case INST_IO:
plink->value.instio.string = pinfo->target;
break;
case VME_IO:
plink->value.vmeio.card = pinfo->hwnums[0];
plink->value.vmeio.signal = pinfo->hwnums[1];
plink->value.vmeio.parm = pinfo->target;
break;
case CAMAC_IO:
plink->value.camacio.b = pinfo->hwnums[0];
plink->value.camacio.c = pinfo->hwnums[1];
plink->value.camacio.n = pinfo->hwnums[2];
plink->value.camacio.a = pinfo->hwnums[3];
plink->value.camacio.f = pinfo->hwnums[4];
plink->value.camacio.parm = pinfo->target;
break;
case RF_IO:
plink->value.rfio.cryo = pinfo->hwnums[0];
plink->value.rfio.micro = pinfo->hwnums[1];
plink->value.rfio.dataset = pinfo->hwnums[2];
plink->value.rfio.element = pinfo->hwnums[3];
break;
case AB_IO:
plink->value.abio.link = pinfo->hwnums[0];
plink->value.abio.adapter = pinfo->hwnums[1];
plink->value.abio.card = pinfo->hwnums[2];
plink->value.abio.signal = pinfo->hwnums[3];
plink->value.abio.parm = pinfo->target;
break;
case GPIB_IO:
plink->value.gpibio.link = pinfo->hwnums[0];
plink->value.gpibio.addr = pinfo->hwnums[1];
plink->value.gpibio.parm = pinfo->target;
break;
case BITBUS_IO:
plink->value.bitbusio.link = pinfo->hwnums[0];
plink->value.bitbusio.node = pinfo->hwnums[1];
plink->value.bitbusio.port = pinfo->hwnums[2];
plink->value.bitbusio.signal = pinfo->hwnums[3];
plink->value.bitbusio.parm = pinfo->target;
break;
case BBGPIB_IO:
plink->value.bbgpibio.link = pinfo->hwnums[0];
plink->value.bbgpibio.bbaddr = pinfo->hwnums[1];
plink->value.bbgpibio.gpibaddr = pinfo->hwnums[2];
plink->value.bbgpibio.parm = pinfo->target;
break;
case VXI_IO:
if(strcmp(pinfo->hwid, "VCS")==0) {
plink->value.vxiio.flag=VXIDYNAMIC;
plink->value.vxiio.frame = pinfo->hwnums[0];
plink->value.vxiio.slot = pinfo->hwnums[1];
plink->value.vxiio.signal = pinfo->hwnums[2];
} else if(strcmp(pinfo->hwid, "VS")==0) {
plink->value.vxiio.flag=VXISTATIC;
plink->value.vxiio.la = pinfo->hwnums[0];
plink->value.vxiio.signal = pinfo->hwnums[1];
} else {
cantProceed("dbSetLinkHW: logic error, unknown VXI_IO variant");
}
plink->value.vxiio.parm = pinfo->target;
break;
default:
cantProceed("dbSetLinkHW: logic error, unhandled link type");
return;
}
plink->type = pinfo->ltype;
pinfo->target = NULL; /* now owned by link field */
}
long dbSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup)
{
int ret = 0;
int link_type = CONSTANT;
if(devsup)
link_type = devsup->link_type;
if(link_type==CONSTANT || link_type==PV_LINK) {
switch(pinfo->ltype) {
case CONSTANT:
dbFreeLinkContents(plink);
dbSetLinkConst(plink, pinfo); break;
case PV_LINK:
dbFreeLinkContents(plink);
dbSetLinkPV(plink, pinfo); break;
default:
errlogMessage("Warning: dbSetLink: forgot to test with dbCanSetLink() or logic error");
goto fail; /* can't assign HW link */
}
} else if(link_type==pinfo->ltype) {
dbFreeLinkContents(plink);
dbSetLinkHW(plink, pinfo);
} else
goto fail;
return ret;
fail:
free(pinfo->target);
pinfo->target = NULL;
return S_dbLib_badField;
}
long dbPutString(DBENTRY *pdbentry,const char *pstring)
@@ -2069,351 +2277,39 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring)
case DBF_FLOAT:
case DBF_DOUBLE:
case DBF_MENU:
case DBF_DEVICE:
status = dbPutStringNum(pdbentry,pstring);
break;
case DBF_DEVICE: {
DBENTRY dbEntry;
char *name;
status = dbPutStringNum(pdbentry, pstring);
if (status) return status;
name = dbGetRelatedField(pdbentry);
if (!name) return 0;
dbCopyEntryContents(pdbentry, &dbEntry);
status = dbFindField(&dbEntry, name);
if (!status)
status = setLinkType(&dbEntry);
dbFinishEntry(&dbEntry);
return status;
}
case DBF_INLINK:
case DBF_OUTLINK:
case DBF_FWDLINK: {
DBLINK *plink;
char string[80];
char *pstr = string;
dbLinkInfo link_info;
DBLINK *plink = (DBLINK *)pfield;
if (!pfield)
return S_dbLib_fieldNotFound;
status = dbParseLink(pstring, pflddes->field_type, &link_info);
plink = (DBLINK *)pfield;
dbFreeLinkContents(plink);
if (stringHasMacro) {
plink->type = MACRO_LINK;
plink->value.macro_link.macroStr = epicsStrDup(pstring);
goto done;
}
if(status==0 && plink->type==CONSTANT && plink->value.constantStr==NULL) {
/* links not yet initialized by dbInitRecordLinks() */
free(plink->text);
plink->text = epicsStrDup(pstring);
free(link_info.target);
if (strcmp(pflddes->name, "INP") == 0 ||
strcmp(pflddes->name, "OUT") == 0) {
status = setLinkType(pdbentry); /* This uses DTYP to look up and set plink->type, necessary for default DTYP */
if (status) {
errMessage(status,"in dbPutString from setLinkType");
return status;
}
/* store link text in case DTYP changes later */
plink->text = malloc(strlen(pstring) + 1);
if (plink->text)
strcpy(plink->text, pstring);
}
if (strlen(pstring) >= sizeof(string)) {
status = S_dbLib_badField;
errMessage(status,
"dbPutString received a string that is too long");
return status;
}
strcpy(pstr, pstring);
/* Strip leading blanks and tabs */
while (*pstr && (*pstr == ' ' || *pstr == '\t')) pstr++;
/* Strip trailing blanks and tabs */
if (pstr) {
int ind;
} else if(status==0) {
/* assignment after init (eg. autosave restore) */
struct dbCommon *prec = pdbentry->precnode->precord;
devSup *devsup = (devSup *)ellNth(&pdbentry->precordType->devList, prec->dtyp+1);
status = dbCanSetLink(plink, &link_info, devsup);
if(status==0)
status = dbSetLink(plink, &link_info, devsup);
}
for (ind = (int) strlen(pstr) - 1; ind >= 0; ind--) {
if (pstr[ind] != ' ' && pstr[ind] != '\t') break;
pstr[ind] = '\0';
}
}
if (!pstr || !*pstr) {
if (plink->type == PV_LINK) dbCvtLinkToConstant(pdbentry);
if (plink->type != CONSTANT) return S_dbLib_badField;
free((void *)plink->value.constantStr);
plink->value.constantStr = NULL;
goto done;
}
switch (plink->type) {
case CONSTANT:
case PV_LINK: {
short ppOpt = 0;
short msOpt = 0;
char *end;
char *enddouble;
char *endlong;
/* Check first to see if string is a constant*/
/*It is a string if epicsStrtod or strtol eats entire string*/
/*leading and trailing blanks have already been stripped*/
(void) epicsStrtod(pstr, &enddouble);
(void) strtol(pstr, &endlong, 0);
if (*enddouble == 0 || *endlong == 0) {
if (plink->type == PV_LINK) dbCvtLinkToConstant(pdbentry);
if (!plink->value.constantStr ||
strlen(plink->value.constantStr) < strlen(pstr)) {
free(plink->value.constantStr);
plink->value.constantStr =
dbCalloc(strlen(pstr) + 1, sizeof(char));
}
strcpy(plink->value.constantStr, pstr);
goto done;
}
if (plink->type==CONSTANT) dbCvtLinkToPvlink(pdbentry);
end = strchr(pstr,' ');
if (end) {
switch (pflddes->field_type) {
case DBF_INLINK: {
if (strstr(end, "NPP")) ppOpt = 0;
else if (strstr(end, "CPP")) ppOpt = pvlOptCPP;
else if (strstr(end, "PP")) ppOpt = pvlOptPP;
else if (strstr(end, "CA")) ppOpt = pvlOptCA;
else if (strstr(end, "CP")) ppOpt = pvlOptCP;
else ppOpt = 0;
if (strstr(end, "NMS")) msOpt = pvlOptNMS;
else if (strstr(end, "MSI")) msOpt = pvlOptMSI;
else if (strstr(end, "MSS")) msOpt = pvlOptMSS;
/*must be the last one:*/ else if (strstr(end, "MS")) msOpt = pvlOptMS;
else msOpt = 0;
*end = 0;
}
break;
case DBF_OUTLINK: {
if (strstr(end, "NPP")) ppOpt = 0;
else if(strstr(end, "PP")) ppOpt = pvlOptPP;
else if(strstr(end, "CA")) ppOpt = pvlOptCA;
else ppOpt = 0;
if (strstr(end, "NMS")) msOpt = pvlOptNMS;
else if(strstr(end, "MSI")) msOpt = pvlOptMSI;
else if(strstr(end, "MSS")) msOpt = pvlOptMSS;
/*must be the last one:*/ else if(strstr(end, "MS")) msOpt = pvlOptMS;
else msOpt = 0;
*end = 0;
}
break;
case DBF_FWDLINK: {
if (strstr(end, "NPP")) ppOpt = 0;
else if (strstr(end, "CA")) ppOpt = pvlOptCA;
else ppOpt = 0;
msOpt = 0;
*end = 0;
}
break;
default:
epicsPrintf("dbPutString: Logic Error\n");
}
}
status = putPvLink(pdbentry,ppOpt|msOpt,pstr);
goto done;
}
/*break; is unnecessary*/
case VME_IO: {
char *end;
if (!(end = strchr(pstr,'#'))) return S_dbLib_badField;
pstr = end + 1;
if (!(end = strchr(pstr,'C'))) return S_dbLib_badField;
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.vmeio.card);
if (!(end = strchr(pstr,'S'))) return S_dbLib_badField;
pstr = end + 1;
cvtDecimalOrHexToShort(pstr, &plink->value.vmeio.signal);
status = putParmString(&plink->value.vmeio.parm, pstr);
}
break;
case CAMAC_IO: {
char *end;
if (!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
pstr = end + 1;
if (!(end = strchr(pstr,'B'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.camacio.b);
if (!(end = strchr(pstr,'C'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.camacio.c);
if (!(end = strchr(pstr,'N'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.camacio.n);
if (!(end = strchr(pstr,'A'))) {
plink->value.camacio.a = 0;
} else {
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.camacio.a);
}
if (!(end = strchr(pstr,'F'))) {
plink->value.camacio.f = 0;
} else {
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.camacio.f);
}
status = putParmString(&plink->value.camacio.parm,pstr);
}
break;
case RF_IO: {
char *end;
if(!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
pstr = end + 1;
if(!(end = strchr(pstr,'R'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.rfio.cryo);
if(!(end = strchr(pstr,'M'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.rfio.micro);
if(!(end = strchr(pstr,'D'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.rfio.dataset);
if(!(end = strchr(pstr,'E'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.rfio.element);
}
break;
case AB_IO: {
char *end;
if(!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
pstr = end + 1;
if(!(end = strchr(pstr,'L'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.abio.link);
if(!(end = strchr(pstr,'A'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.abio.adapter);
if(!(end = strchr(pstr,'C'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.abio.card);
if(!(end = strchr(pstr,'S'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.abio.signal);
status = putParmString(&plink->value.abio.parm,pstr);
}
break;
case GPIB_IO: {
char *end;
if(!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
pstr = end + 1;
if(!(end = strchr(pstr,'L'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.gpibio.link);
if(!(end = strchr(pstr,'A'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.gpibio.addr);
status = putParmString(&plink->value.gpibio.parm,pstr);
}
break;
case BITBUS_IO: {
/* jbk - the bbgpib struct uses unsigned char's instead
of short, so read values into short and then convert */
char *end;
short tmp_val;
if(!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
pstr = end + 1;
if(!(end = strchr(pstr,'L'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&tmp_val);
plink->value.bitbusio.link=(unsigned char)tmp_val;
if(!(end = strchr(pstr,'N'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&tmp_val);
plink->value.bitbusio.node=(unsigned char)tmp_val;
if(!(end = strchr(pstr,'P'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&tmp_val);
plink->value.bitbusio.port=(unsigned char)tmp_val;
if(!(end = strchr(pstr,'S'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&tmp_val);
plink->value.bitbusio.signal=(unsigned char)tmp_val;
status = putParmString(&plink->value.bitbusio.parm,pstr);
}
break;
case BBGPIB_IO: {
/* jbk - the bbgpib struct uses unsigned char's instead
of short, so read values into short and then convert */
char *end;
short tmp_val;
if(!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
pstr = end + 1;
if(!(end = strchr(pstr,'L'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&tmp_val);
plink->value.bbgpibio.link=(unsigned char)tmp_val;
if(!(end = strchr(pstr,'B'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&tmp_val);
plink->value.bbgpibio.bbaddr=(unsigned char)tmp_val;
if(!(end = strchr(pstr,'G'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&tmp_val);
plink->value.bbgpibio.gpibaddr=(unsigned char)tmp_val;
status = putParmString(&plink->value.bbgpibio.parm,pstr);
}
break;
case VXI_IO: {
char *end;
if(!(end = strchr(pstr,'#'))) return (S_dbLib_badField);
pstr = end + 1;
memset((char *)&plink->value.vxiio,0,sizeof(struct vxiio));
plink->value.vxiio.parm = pNullString;
if(!((end = strchr(pstr,'C'))&&(end < strchr(pstr,'@')) )) {
plink->value.vxiio.flag = VXISTATIC;
if(!(end = strchr(pstr,'V'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.vxiio.la);
} else {
plink->value.vxiio.flag = VXIDYNAMIC;
if(!(end = strchr(pstr,'V'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.vxiio.frame);
if(!(end = strchr(pstr,'C'))) return (S_dbLib_badField);
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.vxiio.slot);
}
if((end = strchr(pstr,'S'))) {
pstr = end + 1;
cvtDecimalOrHexToShort(pstr,&plink->value.vxiio.signal);
} else {
plink->value.vxiio.signal = 0;
}
status = putParmString(&plink->value.vxiio.parm,pstr);
}
break;
case INST_IO: {
status = putParmString(&plink->value.instio.string, pstr);
}
break;
}
}
}
break;
default:
return S_dbLib_badField;
}
done:
if (!status && strcmp(pflddes->name, "VAL") == 0) {
DBENTRY dbentry;
+33
View File
@@ -36,6 +36,39 @@ char *dbRecordName(DBENTRY *pdbentry);
char *dbGetStringNum(DBENTRY *pdbentry);
long dbPutStringNum(DBENTRY *pdbentry,const char *pstring);
typedef struct dbLinkInfo {
short ltype;
/* full link string for CONSTANT and PV_LINK,
* parm string for HW links*/
char *target;
/* for PV_LINK */
short modifiers;
/* HW links */
char hwid[6]; /* one extra element for a nil */
int hwnums[5];
} dbLinkInfo;
long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec);
/* Parse link string. no record locks needed.
* on success caller must free pinfo->target
*/
epicsShareFunc long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo);
/* Check if link type allow the parsed link value pinfo
* to be assigned to the given link.
* Record containing plink must be locked.
* Frees pinfo->target on failure.
*/
long dbCanSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *devsup);
/* Set link field. source record must be locked (target record too
* when a DB_LINK is created)
* Unconditionally takes ownership of pinfo->target
*/
long dbSetLink(DBLINK *plink, dbLinkInfo *pinfo, devSup *dset);
/* The following is for path */
typedef struct dbPathNode {
ELLNODE node;
+15 -9
View File
@@ -86,7 +86,14 @@ static void initDatabase(void);
static void initialProcess(void);
static void exitDatabase(void *dummy);
/*
* Iterate through all record instances (but not aliases),
* calling a function for each one.
*/
typedef void (*recIterFunc)(dbRecordType *rtyp, dbCommon *prec, void *user);
static void iterateRecords(recIterFunc func, void *user);
/*
* Initialize EPICS on the IOC.
*/
@@ -126,8 +133,14 @@ static int iocBuild_1(void)
return 0;
}
static void prepareLinks(dbRecordType *rtyp, dbCommon *prec, void *junk)
{
dbInitRecordLinks(rtyp, prec);
}
static int iocBuild_2(void)
{
iterateRecords(prepareLinks, NULL);
initHookAnnounce(initHookAfterCaLinkInit);
initDrvSup();
@@ -419,12 +432,6 @@ static void finishDevSup(void)
}
}
}
/*
* Iterate through all record instances (but not aliases),
* calling a function for each one.
*/
typedef void (*recIterFunc)(dbRecordType *rtyp, dbCommon *prec, void *user);
static void iterateRecords(recIterFunc func, void *user)
{
@@ -490,8 +497,7 @@ static void doResolveLinks(dbRecordType *pdbRecordType, dbCommon *precord,
dbFldDes *pdbFldDes = papFldDes[link_ind[j]];
DBLINK *plink = (DBLINK *)((char *)precord + pdbFldDes->offset);
if (ellCount(&precord->rdes->devList) > 0 &&
(strcmp(pdbFldDes->name, "INP") == 0 || strcmp(pdbFldDes->name, "OUT") == 0)) {
if (ellCount(&precord->rdes->devList) > 0 && pdbFldDes->isDevLink) {
devSup *pdevSup = dbDTYPtoDevSup(pdbRecordType, precord->dtyp);
if (pdevSup) {