From 8cc20393f1e34cf43678dd82f2b29fa5e3522cf0 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Fri, 5 Jun 2020 11:00:58 +0200 Subject: [PATCH 01/19] fix dbr size of empty arrays. Fixes caget returning non 0 in first element --- modules/ca/src/client/db_access.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ca/src/client/db_access.h b/modules/ca/src/client/db_access.h index 810f82ff7..ad10a88e1 100644 --- a/modules/ca/src/client/db_access.h +++ b/modules/ca/src/client/db_access.h @@ -516,7 +516,7 @@ struct dbr_ctrl_double{ }; #define dbr_size_n(TYPE,COUNT)\ -((unsigned)((COUNT)<=0?dbr_size[TYPE]:dbr_size[TYPE]+((COUNT)-1)*dbr_value_size[TYPE])) +((unsigned)((COUNT)<0?dbr_size[TYPE]:dbr_size[TYPE]+((COUNT)-1)*dbr_value_size[TYPE])) /* size for each type - array indexed by the DBR_ type code */ LIBCA_API extern const unsigned short dbr_size[]; From 19c50d4c3db32668b4d5bebfb7e6d15e87cd10f4 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Fri, 5 Jun 2020 16:01:14 +0200 Subject: [PATCH 02/19] fix aai and waveform soft device support to support reading empty arrays --- modules/database/src/std/dev/devAaiSoft.c | 11 ++++++++--- modules/database/src/std/dev/devWfSoft.c | 7 +++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/modules/database/src/std/dev/devAaiSoft.c b/modules/database/src/std/dev/devAaiSoft.c index 1f5765650..0fbb1148e 100644 --- a/modules/database/src/std/dev/devAaiSoft.c +++ b/modules/database/src/std/dev/devAaiSoft.c @@ -60,9 +60,10 @@ static long init_record(dbCommon *pcommon) } status = dbLoadLinkArray(plink, prec->ftvl, prec->bptr, &nRequest); - if (!status && nRequest > 0) { + if (!status) { prec->nord = nRequest; prec->udf = FALSE; + return status; } } return 0; @@ -74,7 +75,7 @@ static long readLocked(struct link *pinp, void *dummy) long nRequest = prec->nelm; long status = dbGetLink(pinp, prec->ftvl, prec->bptr, 0, &nRequest); - if (!status && nRequest > 0) { + if (!status) { prec->nord = nRequest; prec->udf = FALSE; @@ -89,8 +90,12 @@ static long read_aai(aaiRecord *prec) { epicsUInt32 nord = prec->nord; struct link *pinp = prec->simm == menuYesNoYES ? &prec->siol : &prec->inp; - long status = dbLinkDoLocked(pinp, readLocked, NULL); + long status; + if (dbLinkIsConstant(pinp)) + return 0; + + status = dbLinkDoLocked(pinp, readLocked, NULL); if (status == S_db_noLSET) status = readLocked(pinp, NULL); diff --git a/modules/database/src/std/dev/devWfSoft.c b/modules/database/src/std/dev/devWfSoft.c index 0a089b831..29a617be3 100644 --- a/modules/database/src/std/dev/devWfSoft.c +++ b/modules/database/src/std/dev/devWfSoft.c @@ -41,7 +41,7 @@ static long init_record(dbCommon *pcommon) long nelm = prec->nelm; long status = dbLoadLinkArray(&prec->inp, prec->ftvl, prec->bptr, &nelm); - if (!status && nelm > 0) { + if (!status) { prec->nord = nelm; prec->udf = FALSE; } @@ -77,11 +77,14 @@ static long read_wf(waveformRecord *prec) rt.ptime = (dbLinkIsConstant(&prec->tsel) && prec->tse == epicsTimeEventDeviceTime) ? &prec->time : NULL; + if (dbLinkIsConstant(&prec->inp)) + return 0; + status = dbLinkDoLocked(&prec->inp, readLocked, &rt); if (status == S_db_noLSET) status = readLocked(&prec->inp, &rt); - if (!status && rt.nRequest > 0) { + if (!status) { prec->nord = rt.nRequest; prec->udf = FALSE; if (nord != prec->nord) From c4c13d8ce03743446154903bd360e0da8991ce67 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Fri, 5 Jun 2020 16:14:02 +0200 Subject: [PATCH 03/19] fix subArray soft device support to support reading empty arrays --- modules/database/src/std/dev/devSASoft.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/database/src/std/dev/devSASoft.c b/modules/database/src/std/dev/devSASoft.c index be32af458..8db192f14 100644 --- a/modules/database/src/std/dev/devSASoft.c +++ b/modules/database/src/std/dev/devSASoft.c @@ -65,7 +65,7 @@ static long init_record(dbCommon *pcommon) status = dbLoadLinkArray(&prec->inp, prec->ftvl, prec->bptr, &nRequest); - if (!status && nRequest > 0) + if (!status) subset(prec, nRequest); return status; @@ -115,7 +115,7 @@ static long read_sa(subArrayRecord *prec) status = readLocked(&prec->inp, &rt); } - if (!status && rt.nRequest > 0) { + if (!status) { subset(prec, rt.nRequest); if (nord != prec->nord) From e4dcd3cefdabc52157ed139e06ec7a6309c55dcb Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Fri, 5 Jun 2020 16:19:10 +0200 Subject: [PATCH 04/19] fix aSub record to support reading empty arrays --- modules/database/src/std/rec/aSubRecord.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/database/src/std/rec/aSubRecord.c b/modules/database/src/std/rec/aSubRecord.c index 666558bbf..1bcbb63e4 100644 --- a/modules/database/src/std/rec/aSubRecord.c +++ b/modules/database/src/std/rec/aSubRecord.c @@ -277,10 +277,9 @@ static long fetch_values(aSubRecord *prec) long nRequest = (&prec->noa)[i]; status = dbGetLink(&(&prec->inpa)[i], (&prec->fta)[i], (&prec->a)[i], 0, &nRequest); - if (nRequest > 0) - (&prec->nea)[i] = nRequest; if (status) return status; + (&prec->nea)[i] = nRequest; } return 0; } From f8035d8d5eb19501b729efd3369a002be94aa7bc Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Mon, 8 Jun 2020 10:36:40 +0200 Subject: [PATCH 05/19] support arrays in dbpf --- modules/database/src/ioc/db/dbTest.c | 43 +++++++++++++++++++++------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/modules/database/src/ioc/db/dbTest.c b/modules/database/src/ioc/db/dbTest.c index 11939545b..9fcbfdf84 100644 --- a/modules/database/src/ioc/db/dbTest.c +++ b/modules/database/src/ioc/db/dbTest.c @@ -363,8 +363,9 @@ long dbpf(const char *pname,const char *pvalue) { DBADDR addr; long status; - short dbrType; - size_t n = 1; + short dbrType = DBR_STRING; + long n = 1; + epicsOldString *array = NULL; if (!pname || !*pname || !pvalue) { printf("Usage: dbpf \"pv name\", \"value\"\n"); @@ -379,16 +380,36 @@ long dbpf(const char *pname,const char *pvalue) return -1; } - if (addr.no_elements > 1 && - (addr.dbr_field_type == DBR_CHAR || addr.dbr_field_type == DBR_UCHAR)) { - dbrType = addr.dbr_field_type; - n = strlen(pvalue) + 1; - } - else { - dbrType = DBR_STRING; - } + if (addr.no_elements > 1) { + if (addr.dbr_field_type == DBR_CHAR || addr.dbr_field_type == DBR_UCHAR) { + dbrType = addr.dbr_field_type; + n = (long)strlen(pvalue) + 1; + } else { + const char *p = pvalue; + epicsOldString *array; - status = dbPutField(&addr, dbrType, pvalue, (long) n); + for (n = 0; *p && n < addr.no_elements; n++) { + while (isspace(*p)) p++; + while (*p && !isspace(*p)) { + if (p[0] == '\\' && p[1]) p++; + p++; + } + } + p = pvalue; + array = dbCalloc(n, sizeof(epicsOldString)); + for (n = 0; *p && n < addr.no_elements; n++) { + char* c = array[n]; + while (isspace(*p)) p++; + while (*p && !isspace(*p)) { + if (p[0] == '\\' && p[1]) p++; + *c++=*p++; + } + } + pvalue = (void*)array; + } + } + status = dbPutField(&addr, dbrType, pvalue, n); + free(array); dbgf(pname); return status; } From a42197f0d670066c63f46b0af2eb3d01e8bb14f5 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Mon, 8 Jun 2020 16:03:27 +0200 Subject: [PATCH 06/19] allow to write empty arrays with caput --- modules/ca/src/client/nciu.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ca/src/client/nciu.cpp b/modules/ca/src/client/nciu.cpp index 0a7e70899..ebf30fec7 100644 --- a/modules/ca/src/client/nciu.cpp +++ b/modules/ca/src/client/nciu.cpp @@ -328,7 +328,7 @@ void nciu::write ( if ( ! this->accessRightState.writePermit() ) { throw cacChannel::noWriteAccess(); } - if ( countIn > this->count || countIn == 0 ) { + if ( countIn > this->count) { throw cacChannel::outOfBounds(); } if ( type == DBR_STRING ) { @@ -349,7 +349,7 @@ cacChannel::ioStatus nciu::write ( if ( ! this->accessRightState.writePermit() ) { throw cacChannel::noWriteAccess(); } - if ( countIn > this->count || countIn == 0 ) { + if ( countIn > this->count) { throw cacChannel::outOfBounds(); } if ( type == DBR_STRING ) { From 3176651c7116b2bbc8aedc0ec28a562c900cfbc3 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Tue, 9 Jun 2020 16:14:49 +0200 Subject: [PATCH 07/19] fix dbGet to fail when reading scalars from empty arrays --- modules/database/src/ioc/db/dbAccess.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c index 9cda401ad..112b6152b 100644 --- a/modules/database/src/ioc/db/dbAccess.c +++ b/modules/database/src/ioc/db/dbAccess.c @@ -945,6 +945,11 @@ long dbGet(DBADDR *paddr, short dbrType, if (offset == 0 && (!nRequest || no_elements == 1)) { if (nRequest) *nRequest = 1; + else if (no_elements < 1) { + status = S_db_onlyOne; + goto done; + } + if (!pfl || pfl->type == dbfl_type_rec) { status = dbFastGetConvertRoutine[field_type][dbrType] (paddr->pfield, pbuf, paddr); From e68e38ad95f6cfae2d619dda179548f2ccc146c2 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Wed, 10 Jun 2020 17:48:09 +0200 Subject: [PATCH 08/19] update RELEASE_NOTES.md about empty arrays --- documentation/RELEASE_NOTES.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 6fd80615a..274d65f4e 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -17,6 +17,36 @@ should also be read to understand what has changed since earlier releases. +### Support for empty arrays + +Several problems with empty arrays have been fixed. + +#### Changed dbr_size_n(TYPE,COUNT) macro + +When called with COUNT=0 the macro no longer returns the number of bytes +required for a scalar (1 element) but for an empty array (0 elements). +Make sure you don't call it with COUNT=0 when you really mean COUNT=1. + +#### Array records + +The soft supports of array records aai, waveform, and subArray as well as +the aSub record type have been fixed to correctly report 0 elements read +when reading empty arrays from an input link. + +#### Array support for dbpf + +The dbpf function now accepts arrays, including empty arrays, as a quoted +whitespace separated list of values. + +#### Scalar records reading from empty arrays + +Scalar records reading from empty arrays via database links are now set to +INVALID/LINK alarm status. +Links have to call dbGet with pnRequest=NULL to be recognised as requests +for scalars. +This changes the semantics of pnRequest=NULL. It is now different from +requesting 1 element, which is counted as an array request and may return +a valid empty array. ## EPICS Release 7.0.4 From dec4fc30d948d4c717430ada3f1366d6dfa204b2 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Mon, 22 Jun 2020 11:30:59 +0200 Subject: [PATCH 09/19] bugfix in dbpf --- modules/database/src/ioc/db/dbTest.c | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/database/src/ioc/db/dbTest.c b/modules/database/src/ioc/db/dbTest.c index 9fcbfdf84..7000c4679 100644 --- a/modules/database/src/ioc/db/dbTest.c +++ b/modules/database/src/ioc/db/dbTest.c @@ -386,7 +386,6 @@ long dbpf(const char *pname,const char *pvalue) n = (long)strlen(pvalue) + 1; } else { const char *p = pvalue; - epicsOldString *array; for (n = 0; *p && n < addr.no_elements; n++) { while (isspace(*p)) p++; From 73b86d49211ac11de35ee654bd3db707951e3bd2 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Mon, 22 Jun 2020 13:23:26 +0200 Subject: [PATCH 10/19] prevent buffer overflow in dbpf --- modules/database/src/ioc/db/dbTest.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/database/src/ioc/db/dbTest.c b/modules/database/src/ioc/db/dbTest.c index 7000c4679..19d392216 100644 --- a/modules/database/src/ioc/db/dbTest.c +++ b/modules/database/src/ioc/db/dbTest.c @@ -399,12 +399,18 @@ long dbpf(const char *pname,const char *pvalue) for (n = 0; *p && n < addr.no_elements; n++) { char* c = array[n]; while (isspace(*p)) p++; + pvalue = p; while (*p && !isspace(*p)) { if (p[0] == '\\' && p[1]) p++; + if (c >= array[n+1]-1) { + printf("Value [%ld] %.*s too long\n", n, (int)(p-pvalue), pvalue); + free(array); + return -1; + } *c++=*p++; } } - pvalue = (void*)array; + pvalue = array[0]; } } status = dbPutField(&addr, dbrType, pvalue, n); From 0353ede517311191400d2b6fff5cdc2846d97c4b Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Sat, 27 Jun 2020 16:05:54 +0200 Subject: [PATCH 11/19] don't use epicsOldString --- modules/database/src/ioc/db/dbTest.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/database/src/ioc/db/dbTest.c b/modules/database/src/ioc/db/dbTest.c index 19d392216..25782a243 100644 --- a/modules/database/src/ioc/db/dbTest.c +++ b/modules/database/src/ioc/db/dbTest.c @@ -365,7 +365,7 @@ long dbpf(const char *pname,const char *pvalue) long status; short dbrType = DBR_STRING; long n = 1; - epicsOldString *array = NULL; + char *array = NULL; if (!pname || !*pname || !pvalue) { printf("Usage: dbpf \"pv name\", \"value\"\n"); @@ -395,14 +395,14 @@ long dbpf(const char *pname,const char *pvalue) } } p = pvalue; - array = dbCalloc(n, sizeof(epicsOldString)); + array = dbCalloc(n, MAX_STRING_SIZE); for (n = 0; *p && n < addr.no_elements; n++) { - char* c = array[n]; + char* c = &array[n*MAX_STRING_SIZE]; while (isspace(*p)) p++; pvalue = p; while (*p && !isspace(*p)) { if (p[0] == '\\' && p[1]) p++; - if (c >= array[n+1]-1) { + if (c >= &array[(n+1)*MAX_STRING_SIZE]-1) { printf("Value [%ld] %.*s too long\n", n, (int)(p-pvalue), pvalue); free(array); return -1; @@ -410,7 +410,7 @@ long dbpf(const char *pname,const char *pvalue) *c++=*p++; } } - pvalue = array[0]; + pvalue = array; } } status = dbPutField(&addr, dbrType, pvalue, n); From 473790124bbf1a5f0cd377082ae71a399caf3a30 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Thu, 13 Feb 2020 17:07:42 +0100 Subject: [PATCH 12/19] bugfix: ai SoftDevice should return error status when get fails --- modules/database/src/std/dev/devAiSoft.c | 3 ++- modules/database/test/std/rec/regressTest.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/database/src/std/dev/devAiSoft.c b/modules/database/src/std/dev/devAiSoft.c index e41d9fedb..a9b32a335 100644 --- a/modules/database/src/std/dev/devAiSoft.c +++ b/modules/database/src/std/dev/devAiSoft.c @@ -85,9 +85,10 @@ static long read_ai(aiRecord *prec) prec->udf = FALSE; prec->dpvt = &devAiSoft; /* Any non-zero value */ + return 2; } else prec->dpvt = NULL; - return 2; + return status; } diff --git a/modules/database/test/std/rec/regressTest.c b/modules/database/test/std/rec/regressTest.c index 661463984..fd4f0a885 100644 --- a/modules/database/test/std/rec/regressTest.c +++ b/modules/database/test/std/rec/regressTest.c @@ -132,7 +132,7 @@ void testCADisconn(void) startRegressTestIoc("badCaLink.db"); - testdbPutFieldOk("ai:disconn.PROC", DBF_LONG, 1); + testdbPutFieldFail(-1, "ai:disconn.PROC", DBF_LONG, 1); testdbGetFieldEqual("ai:disconn.SEVR", DBF_LONG, INVALID_ALARM); testdbGetFieldEqual("ai:disconn.STAT", DBF_LONG, LINK_ALARM); } From 0a1fb25e6bb9523f69b69d845706028c35ac72ca Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Mon, 29 Jun 2020 22:23:21 +0200 Subject: [PATCH 13/19] fix dbCaGetLink to fail when reading scalars from empty arrays --- modules/database/src/ioc/db/dbCa.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/database/src/ioc/db/dbCa.c b/modules/database/src/ioc/db/dbCa.c index 4ae39bbce..28e0df6d8 100644 --- a/modules/database/src/ioc/db/dbCa.c +++ b/modules/database/src/ioc/db/dbCa.c @@ -410,9 +410,15 @@ long dbCaGetLink(struct link *plink, short dbrType, void *pdest, goto done; } newType = dbDBRoldToDBFnew[pca->dbrType]; - if (!nelements || *nelements == 1) { + if (!nelements) { long (*fConvert)(const void *from, void *to, struct dbAddr *paddr); + if (pca->usedelements < 1) { + pca->sevr = INVALID_ALARM; + pca->stat = LINK_ALARM; + status = -1; + goto done; + } fConvert = dbFastGetConvertRoutine[newType][dbrType]; assert(pca->pgetNative); status = fConvert(pca->pgetNative, pdest, 0); From e5a48f152a09f72ea01577efbfdd5a174c878778 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Mon, 29 Jun 2020 23:00:30 +0200 Subject: [PATCH 14/19] RELEASE_NOTES updated --- documentation/RELEASE_NOTES.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 274d65f4e..03021e482 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -40,13 +40,12 @@ whitespace separated list of values. #### Scalar records reading from empty arrays -Scalar records reading from empty arrays via database links are now set to -INVALID/LINK alarm status. -Links have to call dbGet with pnRequest=NULL to be recognised as requests +Scalar records reading from empty arrays are now set to INVALID/LINK alarm +status. +Links have to call dbGetLink with pnRequest=NULL to be recognised as requests for scalars. This changes the semantics of pnRequest=NULL. It is now different from -requesting 1 element, which is counted as an array request and may return -a valid empty array. +requesting up to 1 array element, which may return a valid empty array. ## EPICS Release 7.0.4 From 12cfd418d62e066e1ea08ef2af6603d27168999d Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Mon, 6 Jul 2020 14:58:00 +0200 Subject: [PATCH 15/19] fix dbPut to set target to INVALID/LINK alarm when writing empty arrays into scalars --- modules/database/src/ioc/db/dbAccess.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c index 112b6152b..4fbfa966e 100644 --- a/modules/database/src/ioc/db/dbAccess.c +++ b/modules/database/src/ioc/db/dbAccess.c @@ -1334,25 +1334,21 @@ long dbPut(DBADDR *paddr, short dbrType, status = prset->get_array_info(paddr, &dummy, &offset); /* paddr->pfield may be modified */ if (status) goto done; - } else - offset = 0; - - if (no_elements <= 1) { - status = dbFastPutConvertRoutine[dbrType][field_type](pbuffer, - paddr->pfield, paddr); - nRequest = 1; - } else { if (no_elements < nRequest) nRequest = no_elements; status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer, nRequest, no_elements, offset); - } - - /* update array info */ - if (!status && - paddr->pfldDes->special == SPC_DBADDR && - prset && prset->put_array_info) { - status = prset->put_array_info(paddr, nRequest); + /* update array info */ + if (!status) + status = prset->put_array_info(paddr, nRequest); + } else { + if (nRequest < 1) { + recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM); + } else { + status = dbFastPutConvertRoutine[dbrType][field_type](pbuffer, + paddr->pfield, paddr); + nRequest = 1; + } } /* Always do special processing if needed */ From 4368697f58a2dda9d94b0d18384120d2b24b9221 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Mon, 13 Jul 2020 14:53:20 +0200 Subject: [PATCH 16/19] Updated RELEASE_NOTES.md --- documentation/RELEASE_NOTES.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 03021e482..6464c7470 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -40,13 +40,21 @@ whitespace separated list of values. #### Scalar records reading from empty arrays -Scalar records reading from empty arrays are now set to INVALID/LINK alarm -status. -Links have to call dbGetLink with pnRequest=NULL to be recognised as requests +Records reading scalar fields from empty arrays are now set to INVALID/LINK +alarm status. +Links have to call dbGetLink with pnRequest=NULL to be recognized as requests for scalars. This changes the semantics of pnRequest=NULL. It is now different from requesting up to 1 array element, which may return a valid empty array. +### Writing empty arrays to scalar records + +Witing an empty array to a scalar field now sets the target record to +INVALID/LINK alarm but does not modify the value. Before, the value used +to be set to 0 (without any alarm). +A target field needs to have the SPC_DBADDR tag to be recognized as an array +field and the record support must define a put_array_info method. + ## EPICS Release 7.0.4 ### Bug fixes From a9731b90f6c5469449dd33085f76aae1bae3fc78 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Fri, 17 Jul 2020 09:12:54 +0200 Subject: [PATCH 17/19] Don't freeze the shell when we are out of memory --- modules/database/src/ioc/db/dbTest.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/database/src/ioc/db/dbTest.c b/modules/database/src/ioc/db/dbTest.c index 25782a243..a312abbf7 100644 --- a/modules/database/src/ioc/db/dbTest.c +++ b/modules/database/src/ioc/db/dbTest.c @@ -395,7 +395,11 @@ long dbpf(const char *pname,const char *pvalue) } } p = pvalue; - array = dbCalloc(n, MAX_STRING_SIZE); + array = calloc(n, MAX_STRING_SIZE); + if (!array) { + printf("Out of memory\n"); + return -1; + } for (n = 0; *p && n < addr.no_elements; n++) { char* c = &array[n*MAX_STRING_SIZE]; while (isspace(*p)) p++; From 77092396369ce5655900817c299953c7f1a1465b Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Fri, 17 Jul 2020 09:26:55 +0200 Subject: [PATCH 18/19] make sure put_array_info exists before using it --- modules/database/src/ioc/db/dbAccess.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c index 4fbfa966e..28273f667 100644 --- a/modules/database/src/ioc/db/dbAccess.c +++ b/modules/database/src/ioc/db/dbAccess.c @@ -1339,7 +1339,7 @@ long dbPut(DBADDR *paddr, short dbrType, status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer, nRequest, no_elements, offset); /* update array info */ - if (!status) + if (!status && prset->put_array_info) status = prset->put_array_info(paddr, nRequest); } else { if (nRequest < 1) { From d1491e0860efc2ea3bd85a9f68cd83f18b575ae0 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Fri, 17 Jul 2020 15:03:53 +0200 Subject: [PATCH 19/19] Use JSON arrays in dbpf --- documentation/RELEASE_NOTES.md | 3 +-- modules/database/src/ioc/db/dbTest.c | 33 ++++++---------------------- 2 files changed, 8 insertions(+), 28 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 6464c7470..fb6f691e3 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -35,8 +35,7 @@ when reading empty arrays from an input link. #### Array support for dbpf -The dbpf function now accepts arrays, including empty arrays, as a quoted -whitespace separated list of values. +The dbpf function now accepts arrays, including empty arrays as a JSON string. #### Scalar records reading from empty arrays diff --git a/modules/database/src/ioc/db/dbTest.c b/modules/database/src/ioc/db/dbTest.c index a312abbf7..9368bfc71 100644 --- a/modules/database/src/ioc/db/dbTest.c +++ b/modules/database/src/ioc/db/dbTest.c @@ -40,6 +40,7 @@ #include "recGbl.h" #include "recSup.h" #include "special.h" +#include "dbConvertJSON.h" #define MAXLINE 80 #define MAXMESS 128 @@ -381,39 +382,19 @@ long dbpf(const char *pname,const char *pvalue) } if (addr.no_elements > 1) { + dbrType = addr.dbr_field_type; if (addr.dbr_field_type == DBR_CHAR || addr.dbr_field_type == DBR_UCHAR) { - dbrType = addr.dbr_field_type; n = (long)strlen(pvalue) + 1; } else { - const char *p = pvalue; - - for (n = 0; *p && n < addr.no_elements; n++) { - while (isspace(*p)) p++; - while (*p && !isspace(*p)) { - if (p[0] == '\\' && p[1]) p++; - p++; - } - } - p = pvalue; - array = calloc(n, MAX_STRING_SIZE); + n = addr.no_elements; + array = calloc(n, dbValueSize(dbrType)); if (!array) { printf("Out of memory\n"); return -1; } - for (n = 0; *p && n < addr.no_elements; n++) { - char* c = &array[n*MAX_STRING_SIZE]; - while (isspace(*p)) p++; - pvalue = p; - while (*p && !isspace(*p)) { - if (p[0] == '\\' && p[1]) p++; - if (c >= &array[(n+1)*MAX_STRING_SIZE]-1) { - printf("Value [%ld] %.*s too long\n", n, (int)(p-pvalue), pvalue); - free(array); - return -1; - } - *c++=*p++; - } - } + status = dbPutConvertJSON(pvalue, dbrType, array, &n); + if (status) + return status; pvalue = array; } }