1313#include <dbDefs.h>
1414#include <iocsh.h>
1515#include <errlog.h>
16+ #include <epicsVersion.h>
1617
1718#include <epicsStdio.h>
1819#include <drvSup.h>
2526
2627#include "caster.h"
2728
29+ #ifndef VERSION_INT
30+ # define VERSION_INT (V ,R ,M ,P ) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
31+ #endif
32+ #ifndef EPICS_VERSION_INT
33+ # define EPICS_VERSION_INT VERSION_INT(EPICS_VERSION, EPICS_REVISION, EPICS_MODIFICATION, EPICS_PATCH_LEVEL)
34+ #endif
35+ #if EPICS_VERSION_INT < VERSION_INT (7 ,0 ,3 ,1 )
36+ static int iocshSetError (int err ) { return err ; }
37+ #endif
38+
2839static caster_t thecaster ;
2940
3041typedef struct {
@@ -75,119 +86,88 @@ static void casthook(initHookState state)
7586 epicsAtExit (& castexit , NULL );
7687}
7788
78- /*
79- Example call: addReccasterEnvVars("SECTOR") or addReccasterEnvVars("SECTOR", "BUILDING")
80- Appends the given env variables to the extra_envs list to be sent in addition to the default_envs array
81- */
82- void addReccasterEnvVars (caster_t * self , int argc , char * * argv )
89+ /* Helper function to add items from iocsh calls to internal linked lists
90+ * self is the caster instance
91+ * itemCount is the number of items in the items array
92+ * items is the array of strings to add to the list
93+ * reccastList is the linked list to add the items to
94+ * funcName is the name of the IOC shell function being called (for error messages)
95+ * itemDesc is string to describe what is being added (for error messages)
96+ */
97+ int addToReccasterLinkedList (caster_t * self , size_t itemCount , const char * * items , ELLLIST * reccastList , const char * funcName , const char * itemDesc )
8398{
84- size_t i , j ;
85- int ret = 0 ;
86-
87- argv ++ ; argc -- ; /* skip function arg */
88- if (argc < 1 ) {
89- errlogSevPrintf (errlogMinor , "At least one argument expected for addReccasterEnvVars\n" );
90- return ;
91- }
99+ size_t i ;
100+ int dup ;
101+ ELLNODE * cur ;
92102
93103 epicsMutexMustLock (self -> lock );
94104 if (self -> shutdown ) {
95105 /* shutdown in progress, silent no-op */
96106 epicsMutexUnlock (self -> lock );
97- return ;
107+ return 0 ;
98108 }
99109 else if (self -> current != casterStateInit ) {
100110 /* Attempt to add after iocInit(), when we may be connected.
101- To fully support, would need to force reconnect or resend w/ updated envs list. */
102- errlogSevPrintf (errlogMinor , "addReccasterEnvVars called after iocInit() when reccaster might already be connected. Not supported\n" );
111+ To fully support, would need to force reconnect or resend w/ updated list. */
112+ errlogSevPrintf (errlogMinor , "%s called after iocInit() when reccaster might already be connected. Not supported\n" , funcName );
103113 epicsMutexUnlock (self -> lock );
104- return ;
114+ return -1 ;
105115 }
106- int new_extra_envs_size = self -> num_extra_envs + argc ;
107- int num_new_extra_envs = self -> num_extra_envs ;
108116
109- char * * new_extra_envs = calloc (new_extra_envs_size , sizeof (* new_extra_envs ));
110- if (new_extra_envs == NULL ) {
111- errlogSevPrintf (errlogMajor , "Error in memory allocation of new_extra_envs from addReccasterEnvVars\n" );
112- epicsMutexUnlock (self -> lock );
113- return ;
114- }
115- /* copy self->extra_envs into new_extra_envs with room for new envs */
116- for (i = 0 ; i < self -> num_extra_envs ; i ++ ) {
117- if ((new_extra_envs [i ] = strdup (self -> extra_envs [i ])) == NULL ) {
118- errlogSevPrintf (errlogMinor , "strdup error for copying %s to new_extra_envs[%zu] from addReccasterEnvVars\n" , self -> extra_envs [i ], i );
119- ret = 1 ;
120- break ;
121- }
122- }
123- int found_dup ;
124117 /* sanitize input - check for dups and empty args */
125- if (!ret ) {
126- for (i = 0 ; i < argc ; i ++ ) {
127- if (argv [i ] == NULL ) {
128- errlogSevPrintf (errlogMinor , "Arg is NULL for addReccasterEnvVars\n" );
129- continue ;
130- }
131- else if (argv [i ][0 ] == '\0' ) {
132- errlogSevPrintf (errlogMinor , "Arg is empty for addReccasterEnvVars\n" );
133- continue ;
134- }
135- found_dup = 0 ;
136- /* check if dup in self->default_envs */
137- for (j = 0 ; default_envs [j ]; j ++ ) {
138- if (strcmp (argv [i ], default_envs [j ]) == 0 ) {
139- found_dup = 1 ;
140- errlogSevPrintf (errlogMinor , "Env var %s is already in env list sent by reccaster by default\n" , argv [i ]);
141- break ;
142- }
143- }
144- if (found_dup ) {
145- continue ;
146- }
147- /* check if dup in self->extra_envs */
148- for (j = 0 ; j < num_new_extra_envs ; j ++ ) {
149- if (new_extra_envs [j ] == NULL ) {
150- continue ;
151- }
152- if (strcmp (argv [i ], new_extra_envs [j ]) == 0 ) {
153- found_dup = 1 ;
154- errlogSevPrintf (errlogMinor , "Env var %s is already in extra_envs list\n" , argv [i ]);
155- break ;
156- }
157- }
158- if (found_dup ) {
159- continue ;
160- }
161- if ((new_extra_envs [num_new_extra_envs ] = strdup (argv [i ])) == NULL ) {
162- errlogSevPrintf (errlogMinor , "strdup error for copying %s to new_extra_envs[%d] from addReccasterEnvVars\n" , argv [i ], num_new_extra_envs );
163- ret = 1 ;
118+ for (i = 0 ; i < itemCount ; i ++ ) {
119+ const size_t arg_len = strlen (items [i ]) + 1 ;
120+ if (items [i ][0 ] == '\0' ) {
121+ errlogSevPrintf (errlogMinor , "Arg is empty for %s\n" , funcName );
122+ continue ;
123+ }
124+ dup = 0 ;
125+ /* check if dup in existing linked list */
126+ for (cur = ellFirst (reccastList ); cur ; cur = ellNext (cur )) {
127+ string_list_t * pitem = CONTAINER (cur , string_list_t , node );
128+ if (strcmp (items [i ], pitem -> item_str ) == 0 ) {
129+ dup = 1 ;
164130 break ;
165131 }
166- /* this is a valid arg and we have added the new env var to our array, increment new_extra_envs count */
167- num_new_extra_envs ++ ;
168132 }
133+ if (dup ) {
134+ errlogSevPrintf (errlogMinor , "%s %s already in list for %s\n" , itemDesc , items [i ], funcName );
135+ continue ;
136+ }
137+ string_list_t * new_node = mallocMustSucceed (sizeof (string_list_t ) + arg_len , funcName );
138+ new_node -> item_str = (char * )(new_node + 1 );
139+ memcpy (new_node -> item_str , items [i ], arg_len );
140+
141+ ellAdd (reccastList , & new_node -> node );
169142 }
170- /* if we have no allocation issues and have at least one new env var that is valid, add to self->extra_envs */
171- if (!ret && num_new_extra_envs > self -> num_extra_envs ) {
172- /* from this point, nothing can fail */
173- char * * tmp ;
174- tmp = self -> extra_envs ; /* swap pointers so we can clean up new_extra_envs on success/failure */
175- self -> extra_envs = new_extra_envs ;
176- new_extra_envs = tmp ;
177-
178- new_extra_envs_size = self -> num_extra_envs ; /* with swap of pointers also swap size */
179- self -> num_extra_envs = num_new_extra_envs ;
180- }
181- /* cleanup new_extra_envs[] on success or failure */
182- for (i = 0 ; i < new_extra_envs_size ; i ++ ) {
183- free (new_extra_envs [i ]);
184- }
185- free (new_extra_envs );
186143 epicsMutexUnlock (self -> lock );
144+ return 0 ;
145+ }
146+
147+ /* Example call: addReccasterEnvVars("SECTOR") or addReccasterEnvVars("SECTOR", "BUILDING")
148+ * Appends the given env variables to the envs list to be sent. This includes some hard-coded env vars sent by default
149+ */
150+ int addReccasterEnvVars (caster_t * self , int argc , char * * argv )
151+ {
152+ argv ++ ; argc -- ; /* skip function arg */
153+ if (argc < 1 ) {
154+ errlogSevPrintf (errlogMinor , "At least one argument expected for addReccasterEnvVars\n" );
155+ return -1 ;
156+ }
157+ return addToReccasterLinkedList (self , argc , (const char * * )argv , & self -> envs , "addReccasterEnvVars" , "Environment variable" );
158+ }
187159
188- if (ret ) {
189- errlogSevPrintf (errlogMajor , "Error in addReccasterEnvVars - reccaster might not send the extra env vars specified\n" );
160+ /* Example call: addReccasterExcludePattern("TEST:*") or addReccasterExcludePattern("TEST:*", "*_")
161+ * Appends the given patterns to the exclude_patterns list so those PVs and their meta-data are not sent
162+ */
163+ int addReccasterExcludePattern (caster_t * self , int argc , char * * argv )
164+ {
165+ argv ++ ; argc -- ; /* skip function arg */
166+ if (argc < 1 ) {
167+ errlogSevPrintf (errlogMinor , "At least one argument expected for addReccasterExcludePattern\n" );
168+ return -1 ;
190169 }
170+ return addToReccasterLinkedList (self , argc , (const char * * )argv , & self -> exclude_patterns , "addReccasterExcludePattern" , "Exclude pattern" );
191171}
192172
193173static const iocshArg addReccasterEnvVarsArg0 = { "environmentVar" , iocshArgArgv };
@@ -205,70 +185,25 @@ static const iocshFuncDef addReccasterEnvVarsFuncDef = {
205185};
206186static void addReccasterEnvVarsCallFunc (const iocshArgBuf * args )
207187{
208- addReccasterEnvVars (& thecaster , args [0 ].aval .ac , args [0 ].aval .av );
209- }
210-
211- void addReccasterExcludePattern (caster_t * self , int argc , char * * argv ) {
212- size_t i ;
213- int dup ;
214- ELLNODE * cur ;
215- argv ++ ; argc -- ; /* skip function arg */
216- if (argc < 1 ) {
217- errlogSevPrintf (errlogMinor , "At least one argument expected for addReccasterExcludePattern\n" );
218- return ;
219- }
220- epicsMutexMustLock (self -> lock );
221- if (self -> shutdown ) {
222- /* shutdown in progress, silent no-op */
223- epicsMutexUnlock (self -> lock );
224- return ;
225- }
226- /* error if called after iocInit() */
227- if (self -> current != casterStateInit ) {
228- errlogSevPrintf (errlogMinor , "addReccasterExcludePattern called after iocInit() when reccaster might already be connected. Not supported\n" );
229- epicsMutexUnlock (self -> lock );
230- return ;
231- }
232-
233- for (i = 0 ; i < argc ; i ++ ) {
234- const size_t arg_len = strlen (argv [i ]) + 1 ;
235- if (argv [i ][0 ] == '\0' ) {
236- errlogSevPrintf (errlogMinor , "Arg is empty for addReccasterExcludePattern\n" );
237- continue ;
238- }
239- /* check duplicates */
240- dup = 0 ;
241- for (cur = ellFirst (& self -> exclude_patterns ); cur ; cur = ellNext (cur )) {
242- const string_list_t * ppattern = CONTAINER (cur , string_list_t , node );
243- if (strcmp (argv [i ], ppattern -> item_str ) == 0 ) {
244- dup = 1 ;
245- break ;
246- }
247- }
248- if (dup ) {
249- errlogSevPrintf (errlogMinor , "Duplicate pattern %s in addReccasterExcludePattern\n" , argv [i ]);
250- continue ;
251- }
252- string_list_t * new_node = mallocMustSucceed (sizeof (string_list_t ) + arg_len , "addReccasterExcludePattern" );
253- new_node -> item_str = (char * )(new_node + 1 );
254- memcpy (new_node -> item_str , argv [i ], arg_len );
255-
256- ellAdd (& self -> exclude_patterns , & new_node -> node );
257- }
258-
259- epicsMutexUnlock (self -> lock );
188+ iocshSetError (addReccasterEnvVars (& thecaster , args [0 ].aval .ac , args [0 ].aval .av ));
260189}
261190
262191static const iocshArg addReccasterExcludePatternArg0 = { "excludePattern" , iocshArgArgv };
263192static const iocshArg * const addReccasterExcludePatternArgs [] = { & addReccasterExcludePatternArg0 };
264193static const iocshFuncDef addReccasterExcludePatternFuncDef = {
265194 "addReccasterExcludePattern" ,
266195 1 ,
267- addReccasterExcludePatternArgs
196+ addReccasterExcludePatternArgs ,
197+ #ifdef IOCSHFUNCDEF_HAS_USAGE
198+ "By default, reccaster will send all PVs on IOC startup.\n"
199+ "This function allows you to exclude PVs by specifying patterns to exclude.\n"
200+ "Must be called before iocInit\n"
201+ "Example: addReccasterExcludePattern 'TEST:*' '*_'\n"
202+ #endif
268203};
269-
270- static void addReccasterExcludePatternCallFunc ( const iocshArgBuf * args ) {
271- addReccasterExcludePattern (& thecaster , args [0 ].aval .ac , args [0 ].aval .av );
204+ static void addReccasterExcludePatternCallFunc ( const iocshArgBuf * args )
205+ {
206+ iocshSetError ( addReccasterExcludePattern (& thecaster , args [0 ].aval .ac , args [0 ].aval .av ) );
272207}
273208
274209static void reccasterRegistrar (void )
0 commit comments