Skip to content

Commit 7b811bc

Browse files
authored
Merge pull request #120 from madelinespark/env_vars_update
Convert addReccasterEnvVars to linked list and create helper function for addReccaster* logic
2 parents 466a55d + c7d5e98 commit 7b811bc

File tree

6 files changed

+199
-231
lines changed

6 files changed

+199
-231
lines changed

client/castApp/src/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ TESTS += testtcp
4545

4646
TESTPROD_HOST += testAddEnvVars
4747
testAddEnvVars_SRCS += testAddEnvVars.c
48+
testAddEnvVars_SRCS += dbcb.c
4849
testAddEnvVars_SYS_LIBS_WIN32 = ws2_32
4950
TESTS += testAddEnvVars
5051

client/castApp/src/caster.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,18 @@ void casterInit(caster_t *self)
114114
self->onmsg = &casterShowMsgDefault;
115115
self->current = casterStateInit;
116116
self->timeout = reccastTimeout;
117+
ellInit(&self->envs);
117118
ellInit(&self->exclude_patterns);
118119

120+
/* add default_envs to envs list which can be expanded by the user with addReccasterEnvVars iocsh function */
121+
addToReccasterLinkedList(self, default_envs_count, default_envs, &self->envs, "casterInit", "Default environment variable");
122+
119123
if(shSocketPair(self->wakeup))
120124
errlogPrintf("Error: casterInit failed to create shutdown socket: %d\n", SOCKERRNO);
121125
}
122126

123127
void casterShutdown(caster_t *self)
124128
{
125-
int i;
126129
epicsUInt32 junk = htonl(0xdeadbeef);
127130

128131
epicsMutexMustLock(self->lock);
@@ -137,13 +140,7 @@ void casterShutdown(caster_t *self)
137140
epicsEventMustWait(self->shutdownEvent);
138141

139142
epicsMutexMustLock(self->lock);
140-
for (i = 0; i < self->num_extra_envs; i++) {
141-
free(self->extra_envs[i]);
142-
}
143-
free(self->extra_envs);
144-
epicsMutexUnlock(self->lock);
145-
146-
epicsMutexMustLock(self->lock);
143+
ellFree(&self->envs);
147144
ellFree(&self->exclude_patterns);
148145
epicsMutexUnlock(self->lock);
149146

client/castApp/src/caster.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ epicsShareExtern double reccastTimeout;
2222
epicsShareExtern double reccastMaxHoldoff;
2323

2424
extern const char* default_envs[];
25+
extern const size_t default_envs_count;
2526

2627
typedef enum {
2728
casterUDPSetup,
@@ -74,9 +75,7 @@ typedef struct _caster_t {
7475
int shutdown;
7576
char lastmsg[MAX_STRING_SIZE];
7677

77-
char **extra_envs;
78-
int num_extra_envs;
79-
78+
ELLLIST envs;
8079
ELLLIST exclude_patterns;
8180

8281
} caster_t;
@@ -107,10 +106,13 @@ epicsShareFunc
107106
int casterPushPDB(void *junk, caster_t *caster);
108107

109108
epicsShareFunc
110-
void addReccasterEnvVars(caster_t* self, int argc, char **argv);
109+
int addToReccasterLinkedList(caster_t* self, size_t itemCount, const char **items, ELLLIST* reccastList, const char* funcName, const char* itemDesc);
110+
111+
epicsShareFunc
112+
int addReccasterEnvVars(caster_t* self, int argc, char **argv);
111113

112114
epicsShareFunc
113-
void addReccasterExcludePattern(caster_t* self, int argc, char **argv);
115+
int addReccasterExcludePattern(caster_t* self, int argc, char **argv);
114116

115117
/* internal */
116118

client/castApp/src/castinit.c

Lines changed: 84 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
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>
@@ -25,6 +26,16 @@
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+
2839
static caster_t thecaster;
2940

3041
typedef 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

193173
static const iocshArg addReccasterEnvVarsArg0 = { "environmentVar", iocshArgArgv };
@@ -205,70 +185,25 @@ static const iocshFuncDef addReccasterEnvVarsFuncDef = {
205185
};
206186
static 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

262191
static const iocshArg addReccasterExcludePatternArg0 = { "excludePattern", iocshArgArgv };
263192
static const iocshArg * const addReccasterExcludePatternArgs[] = { &addReccasterExcludePatternArg0 };
264193
static 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

274209
static void reccasterRegistrar(void)

0 commit comments

Comments
 (0)