EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  <20202021  2022  2023  2024  Index 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  <20202021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: [Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0
From: Dirk Zimoch via Core-talk <core-talk at aps.anl.gov>
To: mp+386175 at code.launchpad.net
Date: Mon, 22 Jun 2020 10:58:23 -0000
Dirk Zimoch has proposed merging ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0.

Requested reviews:
  EPICS Core Developers (epics-core)

For more details, see:
https://code.launchpad.net/~dirk.zimoch/epics-base/+git/epics-base/+merge/386175
-- 
Your team EPICS Core Developers is requested to review the proposed merge of ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0.
diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md
index 6fd8061..274d65f 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.
 
 <!-- Insert new items immediately below here ... -->
 
+### 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
 
diff --git a/modules/ca/src/client/db_access.h b/modules/ca/src/client/db_access.h
index 810f82f..ad10a88 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[];
diff --git a/modules/ca/src/client/nciu.cpp b/modules/ca/src/client/nciu.cpp
index 0a7e708..ebf30fe 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 ) {
diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c
index 9cda401..112b615 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);
diff --git a/modules/database/src/ioc/db/dbTest.c b/modules/database/src/ioc/db/dbTest.c
index 1193954..7000c46 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,35 @@ 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;
+
+            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, (long) n);
+    status = dbPutField(&addr, dbrType, pvalue, n);
+    free(array);
     dbgf(pname);
     return status;
 }
diff --git a/modules/database/src/std/dev/devAaiSoft.c b/modules/database/src/std/dev/devAaiSoft.c
index 1f57656..0fbb114 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/devSASoft.c b/modules/database/src/std/dev/devSASoft.c
index be32af4..8db192f 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)
diff --git a/modules/database/src/std/dev/devWfSoft.c b/modules/database/src/std/dev/devWfSoft.c
index 0a089b8..29a617b 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)
diff --git a/modules/database/src/std/rec/aSubRecord.c b/modules/database/src/std/rec/aSubRecord.c
index 666558b..1bcbb63 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;
 }

Replies:
Re: [Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0 mdavidsaver via Core-talk
Re: [Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0 Dirk Zimoch via Core-talk
Re: [Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0 Dirk Zimoch via Core-talk
Re: [Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0 Dirk Zimoch via Core-talk
Re: [Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0 Dirk Zimoch via Core-talk
Re: [Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0 Dirk Zimoch via Core-talk
Re: [Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0 Dirk Zimoch via Core-talk
Re: [Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0 Dirk Zimoch via Core-talk
Re: [Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0 Dirk Zimoch via Core-talk
Re: [Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0 Dirk Zimoch via Core-talk
Re: [Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0 Dirk Zimoch via Core-talk
Re: [Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0 Dirk Zimoch via Core-talk
Re: [Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0 Dirk Zimoch via Core-talk
Re: [Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0 Dirk Zimoch via Core-talk
[Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0 noreply--- via Core-talk

Navigate by Date:
Prev: [Bug 1881563] Re: Empty arrays have undefined behavior Dirk Zimoch via Core-talk
Next: Build failed in Jenkins: epics-pvData-mac #186 APS Jenkins via Core-talk
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  <20202021  2022  2023  2024 
Navigate by Thread:
Prev: Build failed: epics-base base-test-reuse-562 AppVeyor via Core-talk
Next: Re: [Merge] ~dirk.zimoch/epics-base:fix_zero_size_arrays into epics-base:7.0 mdavidsaver via Core-talk
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  <20202021  2022  2023  2024 
ANJ, 18 Nov 2020 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·