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  2020  <20212022  2023  2024  Index 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  <20212022  2023  2024 
<== Date ==> <== Thread ==>

Subject: [Merge] ~dirk.zimoch/epics-base:chfPluginImprovements into epics-base:7.0
From: Dirk Zimoch via Core-talk <core-talk at aps.anl.gov>
To: mp+399636 at code.launchpad.net
Date: Mon, 15 Mar 2021 10:11:22 -0000
Dirk Zimoch has proposed merging ~dirk.zimoch/epics-base:chfPluginImprovements into epics-base:7.0.

Commit message:
Improved channel filter plugin interface

Requested reviews:
  EPICS Core Developers (epics-core)

For more details, see:
https://code.launchpad.net/~dirk.zimoch/epics-base/+git/epics-base/+merge/399636

Allow string arguments with arbitrarily long strings.
In addition to the chfPluginArgString argument type which works on fixed size char array members, chfPluginArgStringAlloc works on char* members. It performs the following actions:
* If a chfPluginArgStringAlloc is provided by the user, the char* member is first NULLed, then filled with a dynamically allocated string (which may fail due to memory shortage)
* If the same char* member may be provided multiple times (maybe under different names), the old value is freed before a new value is written.
* When the structure is released (before freePvt is called), the allocated strings are automatically freed and the char* member NULLed.
* If the parameter is optional and not provided my the user, the pointer is left untouched, allowing to initialize the char* member with a static string as a default value.

-- 
Your team EPICS Core Developers is requested to review the proposed merge of ~dirk.zimoch/epics-base:chfPluginImprovements into epics-base:7.0.
diff --git a/modules/database/src/ioc/db/chfPlugin.c b/modules/database/src/ioc/db/chfPlugin.c
index b4ab72c..a15fd35 100644
--- a/modules/database/src/ioc/db/chfPlugin.c
+++ b/modules/database/src/ioc/db/chfPlugin.c
@@ -71,6 +71,7 @@ store_integer_value(const chfPluginArgDef *opt, char *user, epicsInt32 val)
     const chfPluginEnumType *emap;
     double *dval;
     char *sval;
+    char **psval;
     int ret;
     char buff[22];              /* 2^64 = 1.8e+19, so 20 digits plus sign max */
 
@@ -105,6 +106,12 @@ store_integer_value(const chfPluginArgDef *opt, char *user, epicsInt32 val)
         strncpy(sval, buff, opt->size-1);
         sval[opt->size-1]='\0';
         break;
+    case chfPluginArgStringAlloc:
+        psval = (char **) (user + opt->dataOffset);
+        sprintf(buff, "%ld", (long)val);
+        free(*psval);
+        *psval = epicsStrDup(buff);
+        break;
     case chfPluginArgEnum:
         eval = (int*) (user + opt->dataOffset);
         for (emap = opt->enums; emap && emap->name; emap++) {
@@ -117,7 +124,7 @@ store_integer_value(const chfPluginArgDef *opt, char *user, epicsInt32 val)
             return -1;
         }
         break;
-    case chfPluginArgInvalid:
+    default:
         return -1;
     }
     return 0;
@@ -132,6 +139,7 @@ static int store_boolean_value(const chfPluginArgDef *opt, char *user, int val)
     epicsInt32 *ival;
     double *dval;
     char *sval;
+    char **psval;
 
 #ifdef DEBUG_CHF
     printf("Got a boolean for %s (type %d): %d\n",
@@ -163,8 +171,12 @@ static int store_boolean_value(const chfPluginArgDef *opt, char *user, int val)
         strncpy(sval, val ? "true" : "false", opt->size - 1);
         sval[opt->size - 1] = '\0';
         break;
-    case chfPluginArgEnum:
-    case chfPluginArgInvalid:
+    case chfPluginArgStringAlloc:
+        psval = (char **) (user + opt->dataOffset);
+        free(*psval);
+        *psval = epicsStrDup(val ? "true" : "false");
+        break;
+    default:
         return -1;
     }
     return 0;
@@ -181,6 +193,7 @@ store_double_value(const chfPluginArgDef *opt, void *vuser, double val)
     epicsInt32 *ival;
     double *dval;
     char *sval;
+    char **psval;
     int i;
 
 #ifdef DEBUG_CHF
@@ -218,8 +231,12 @@ store_double_value(const chfPluginArgDef *opt, void *vuser, double val)
             return -1;
         }
         break;
-    case chfPluginArgEnum:
-    case chfPluginArgInvalid:
+    case chfPluginArgStringAlloc:
+        psval = (char **) (user + opt->dataOffset);
+        *psval = realloc(psval, 24);
+        if (*psval) epicsSnprintf(*psval, 24, "%.17g", val);
+        break;
+    default:
         return -1;
     }
     return 0;
@@ -238,6 +255,7 @@ store_string_value(const chfPluginArgDef *opt, char *user, const char *val,
     const chfPluginEnumType *emap;
     double *dval;
     char *sval;
+    char **psval;
     char *end;
     size_t i;
 
@@ -247,6 +265,7 @@ store_string_value(const chfPluginArgDef *opt, char *user, const char *val,
 #endif
 
     if (!opt->convert && opt->optType != chfPluginArgString &&
+        opt->optType != chfPluginArgStringAlloc &&
         opt->optType != chfPluginArgEnum) {
         return -1;
     }
@@ -280,6 +299,11 @@ store_string_value(const chfPluginArgDef *opt, char *user, const char *val,
         strncpy(sval, val, i);
         sval[i] = '\0';
         break;
+    case chfPluginArgStringAlloc:
+        psval = (char **) (user + opt->dataOffset);
+        free(*psval);
+        *psval = epicsStrnDup(val, len);
+        break;
     case chfPluginArgEnum:
         eval = (int*) (user + opt->dataOffset);
         for (emap = opt->enums; emap && emap->name; emap++) {
@@ -292,7 +316,7 @@ store_string_value(const chfPluginArgDef *opt, char *user, const char *val,
             return -1;
         }
         break;
-    case chfPluginArgInvalid:
+    default:
         return -1;
     }
     return 0;
@@ -352,13 +376,30 @@ static parse_result parse_start(chFilter *filter)
     return parse_stop;
 }
 
+static void freePvt(chFilter *filter) {
+    chfPlugin *p = (chfPlugin*) filter->plug->puser;
+    chfFilter *f = (chfFilter*) filter->puser;
+    int i;
+
+    /* free all chfPluginArgStringAlloc options we had allocated */
+    for(i = 0; i < p->nopts; i++) {
+        if (p->opts[i].optType == chfPluginArgStringAlloc &&
+            (f->found[i/32] & (1<<(i%32)))) {
+            char **psval = (char **) ((char*) f->puser + p->opts[i].dataOffset);
+            free(*psval);
+            *psval = NULL;
+        }
+    }
+    if (p->pif->freePvt) p->pif->freePvt(f->puser);
+}
+
 static void parse_abort(chFilter *filter) {
     chfPlugin *p = (chfPlugin*) filter->plug->puser;
     chfFilter *f = (chfFilter*) filter->puser;
 
     /* Call the plugin to tell it we're aborting */
     if (p->pif->parse_error) p->pif->parse_error(f->puser);
-    if (p->pif->freePvt) p->pif->freePvt(f->puser);
+    freePvt(filter);
     freeInstanceData(f);
 }
 
@@ -372,7 +413,7 @@ static parse_result parse_end(chFilter *filter)
     for(i = 0; i < (p->nopts/32)+1; i++) {
         if ((f->found[i] & p->required[i]) != p->required[i]) {
             if (p->pif->parse_error) p->pif->parse_error(f->puser);
-            if (p->pif->freePvt) p->pif->freePvt(f->puser);
+            freePvt(filter);
             freeInstanceData(f);
             return parse_stop;
         }
@@ -381,7 +422,7 @@ static parse_result parse_end(chFilter *filter)
     /* Call the plugin to tell it we're done */
     if (p->pif->parse_ok) {
         if (p->pif->parse_ok(f->puser)) {
-            if (p->pif->freePvt) p->pif->freePvt(f->puser);
+            freePvt(filter);
             freeInstanceData(f);
             return parse_stop;
         }
@@ -486,6 +527,11 @@ parse_map_key(chFilter *filter, const char *key, size_t stringLen)
              || cur->dataOffset == opts[i].dataOffset)
             f->found[j/32] |= 1<<(j%32);
     }
+    /* NULL all found chfPluginArgStringAlloc options */
+    if (opts[i].optType == chfPluginArgStringAlloc) {
+        char **psval = (char **) ((char*) f->puser + opts[i].dataOffset);
+        *psval = NULL;
+    }
 
     return parse_continue;
 }
@@ -546,7 +592,7 @@ static void channel_close(chFilter *filter)
     chfFilter *f =  (chfFilter*) filter->puser;
 
     if (p->pif->channel_close) p->pif->channel_close(filter->chan, f->puser);
-    if (p->pif->freePvt) p->pif->freePvt(f->puser);
+    freePvt(filter);
     free(f->found);
     free(f);         /* FIXME: Use a free-list */
 }
@@ -650,7 +696,16 @@ chfPluginRegister(const char* key, const chfPluginIf *pif,
                 return -1;
             }
             break;
-        case chfPluginArgInvalid:
+        case chfPluginArgStringAlloc:
+            if (cur->size != sizeof(char*)) {
+                  /* Catch if someone has given us a something else than a pointer
+                   */
+                errlogPrintf("Plugin %s: %d bytes not a pointer type for string %s\n",
+                             key, cur->size, cur->name);
+                return -1;
+            }
+            break;
+        default:
             errlogPrintf("Plugin %s: storage type for %s is not defined\n",
                          key, cur->name);
             return -1;
diff --git a/modules/database/src/ioc/db/chfPlugin.h b/modules/database/src/ioc/db/chfPlugin.h
index 8fe156f..e3dced0 100644
--- a/modules/database/src/ioc/db/chfPlugin.h
+++ b/modules/database/src/ioc/db/chfPlugin.h
@@ -52,6 +52,7 @@ struct db_field_log;
  *   epicsInt32 ival2;
  *   int        enumval;
  *   char       strval[20];
+ *   char*      str;
  *   char       boolval;
  * } myStruct;
  *
@@ -64,6 +65,7 @@ struct db_field_log;
  *   chfInt32   (myStruct, ival2,   "Second"  , 1, 0),
  *   chfDouble  (myStruct, dval,    "Double"  , 1, 0),
  *   chfString  (myStruct, strval , "String"  , 1, 0),
+ *   chfStringAlloc(myStruct, str , "String"  , 1, 0),
  *   chfEnum    (myStruct, enumval, "Color"   , 1, 0, colorEnum),
  *   chfBoolean (myStruct, boolval, "Bool"    , 1, 0),
  *   chfPluginEnd
@@ -225,7 +227,8 @@ typedef enum chfPluginArg {
     chfPluginArgInt32,
     chfPluginArgDouble,
     chfPluginArgString,
-    chfPluginArgEnum
+    chfPluginArgEnum,
+    chfPluginArgStringAlloc
 } chfPluginArg;
 
 typedef struct chfPluginEnumType {
@@ -268,6 +271,10 @@ typedef struct chfPluginArgDef {
     {Name, chfPluginArgEnum, Req, Conv, 0, 0, 0, \
     OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), Enums}
 
+#define chfStringAlloc(Struct, Member, Name, Req, Conv) \
+    {Name, chfPluginArgStringAlloc, Req, Conv, 0, 0, 0, \
+    OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
+
 /* Tagged arguments */
 
 #define chfTagInt32(Struct, Member, Name, Tag, Choice, Req, Conv) \
@@ -290,6 +297,10 @@ typedef struct chfPluginArgDef {
     {Name, chfPluginArgEnum, Req, Conv, 1, OFFSET(Struct, Tag), Choice, \
     OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), Enums}
 
+#define chfTagStringAlloc(Struct, Member, Name, Tag, Choice, Req, Conv) \
+    {Name, chfPluginArgStringAlloc, Req, Conv, 1, OFFSET(Struct, Tag), Choice, \
+    OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
+
 #define chfPluginArgEnd {0}
 
 /* Extra output when parsing and converting */

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

Navigate by Date:
Prev: Build failed: EPICS Base 7 base-7.0-248 AppVeyor via Core-talk
Next: Re: [Merge] ~dirk.zimoch/epics-base:chfPluginImprovements into epics-base:7.0 Dirk Zimoch via Core-talk
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  <20212022  2023  2024 
Navigate by Thread:
Prev: Build failed: EPICS Base 7 base-7.0-248 AppVeyor via Core-talk
Next: Re: [Merge] ~dirk.zimoch/epics-base:chfPluginImprovements into epics-base:7.0 Dirk Zimoch via Core-talk
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  <20212022  2023  2024 
ANJ, 09 Apr 2021 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·