Merge ~dirk.zimoch/epics-base:FixShellCommands into ~epics-core/epics-base/+git/epics-base:7.0
- Git
- lp:~dirk.zimoch/epics-base
- FixShellCommands
- Merge into 7.0
Status: | Merged |
---|---|
Approved by: | Andrew Johnson |
Approved revision: | 4190f38db0d88264e2f88a7962880a6dfea09db6 |
Merged at revision: | f0bbae1767f56875beb6cad9fe3c9088725c7fa3 |
Proposed branch: | ~dirk.zimoch/epics-base:FixShellCommands |
Merge into: | ~epics-core/epics-base/+git/epics-base:7.0 |
Diff against target: |
349 lines (+96/-15) 12 files modified
modules/database/src/ioc/db/dbAccess.c (+10/-1) modules/database/src/ioc/db/dbBkpt.c (+12/-0) modules/database/src/ioc/db/dbNotify.c (+5/-1) modules/database/src/ioc/db/dbState.c (+6/-0) modules/database/src/ioc/db/db_test.c (+12/-0) modules/database/src/ioc/misc/dlload.c (+8/-3) modules/libcom/src/iocsh/iocsh.h (+7/-0) modules/libcom/src/iocsh/libComRegister.c (+28/-10) modules/libcom/src/osi/os/Darwin/osdEnv.c (+1/-0) modules/libcom/src/osi/os/default/osdEnv.c (+1/-0) modules/libcom/src/osi/os/iOS/osdEnv.c (+1/-0) modules/libcom/src/osi/os/vxWorks/osdEnv.c (+5/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andrew Johnson | Approve | ||
Review via email: mp+355761@code.launchpad.net |
Commit message
Fix several ioc shell functions.
Description of the change
The functions 'echo', 'dlload', 'epicsParamShow', 'setIocLogDisable' and 'errlog' which are available in iocsh were missing in the vxWorks shell. Calling 'errlog' caused a crash because of a thread with that name. These functions have now been added to the vxWorks shell.
Several functions showed buggy behaviour or printed hard to understand error messages when being called without arguments.
* 'epicsEnvSet' without arguments used to set *NULL to *NULL causing problems later
* 'dbLoadDatabase' and 'dbLoadRecords' printed: "dbRead opening file (null)"
* 'dbap', 'dbb' and 'dbd' printed: "Record (null) not found"
* 'gft', 'pft' and 'tpn' printed: "Channel couldn't be created"
* 'dbtpn' printed: "dbtpn: No such channel" but without newline.
They all now print a "Usage: ..." message.
BTW: I found that all the tests for those functions did not include missing (NULL) mandatory string arguments. I suggest to add that case to the tests for every shell function.
Not fixed:
* 'var' is not available on the vxWorks shell but would be difficult to implement.
* 'epicsThreadSleep' called on the vxWorks shell without arguments sleeps for an unpredictable period. This is a problem of using double type arguments on the vxWorks shell.
Andrew Johnson (anj) wrote : | # |
Dirk Zimoch (dirk.zimoch) wrote : | # |
Hi Andrew,
It all stared when testing EPICS 7 on vxWorks, thus I am a bit focused on vxWorks.
If you do skip a string argument in iocsh, a NULL is passed to the underlying C function if the *Func wrapper does not handle this case separately.
On a Linux IOC I get this:
epics> epicsEnvSet
Missing environment variable name argument.
So this one indeed prints a good error message.
But:
epics> dbLoadDatabase
filename=
dbRead opening file (null)
epics> dbb
BKPT> Record (null) not found
epics> gft
Channel couldn't be created
epics> dbtpn
dbtpn: No such channelepics>
epics> dbStateCreate
Segmentation fault
I will remove the message from dbStateCreate().
dlload on vxWorks does already print a useful error message:
-> dlload
epicsLoadLibrary failed: S_ioLib_NO_FILENAME
value = 45 = 0x2d = '-'
But I can add a "Usage:" message as well.
You are right about the (). I will remove them.
I will change the usage messages to remove the () but keep the "". The iocsh users probably know that they are not really necessary. What about optional parameters? Put them in []? But that may confuse the inexperienced user who might then type literal [].
Dirk
Dirk Zimoch (dirk.zimoch) wrote : | # |
dbStateFind() is not a shell command but should probably check for NULL as well. I'll add it.
Dirk Zimoch (dirk.zimoch) wrote : | # |
'gft', 'pft' and 'tpn' used to print a usage message in 3.14:
usage "pv name","value"
But that had been changed to "Channel couldn't be created" in 3.15.
Dirk Zimoch (dirk.zimoch) wrote : | # |
Also 'pft' and 'tpn' had not checked for a 'value' argument.
In a Linux IOC:
epics> pft existing_record
Segmentation fault
Dirk Zimoch (dirk.zimoch) wrote : | # |
Apropos epicsEnvSet: I have got requests for a method to remove environment variables. At the moment that is not possible, but would be useful for some scripts. Currently one can only set environment variables to an empty string, but that does not trigger the default value is $(variable=default) expansions.
I propose to use epicsEnvSet with a missing value argument to delete the variable, but I have to check if it possible for all architectures. Some have unsetenv(), some support setenv("variable") without "=value". In vxWorks 5 I had to use a hack (destroy the name by setting the first char to 0).
Should I add that feature here or make a new pull request?
Andrew Johnson (anj) wrote : | # |
I think setting an environment variable to an empty string needs to be allowed (without deleting it). Can I request that you add a new command epicsEnvUnset, and since it will affect more than just VxWorks I think a new merge proposal for that from a separate branch would be appropriate. You can tell Launchpad 'this merge proposal depends on that one having already been applied' to save effort and merge conflicts if you need to.
Thanks!
- Andrew
Dirk Zimoch (dirk.zimoch) wrote : | # |
Setting a variable to an empty string would not be a problem even without a separate command, because "" is different from NULL:
Empty string:
epicsEnvSet "var",""
Delete:
epicsEnvSet "var"
(Work for both vxWorks shell and iocsh.)
But I will implement epicsEnvUnset because it is the cleaner interface.
Andrew Johnson (anj) wrote : | # |
I really don't like adding "#ifdef vxWorks" blocks like this does. We have mechanisms that avoid having such blocks of OS-specific code by putting OS-specific routines in OS-specific source files or by defining OS-specific macros. As a result I can do a git grep '#ifdef vxWorks' on the 7.0 tree and the only hits it finds are in test programs. Also some of the additions here are duplicating code from other routines in the same file, which is another code smell from this merge request.
Maybe we could add a macro to iocsh.h for routines that should be exported for VxWorks, so that for example the dlload command could be implemented like this:
static const iocshFuncDef dlloadFuncDef = {"dlload", 1, dlloadArgs};
IOCSH_STATIC_FUNC void dlload(const char* name)
{
if (!name || !*name) {
}
else if (!epicsLoadLibr
}
}
static void dlloadCallFunc(
{
dlload(
}
static void dlloadRegistar(
The IOCSH_STATIC_FUNC macro would expand to static EPICS_ALWAYS_INLINE on everything except VxWorks where it would be empty (Hmm, should GeSys users get these routines as well?). The body of the function is no longer duplicated, there's nothing here which is VxWorks-specific, and if GeSys does need these functions we only have to edit the iocsh.h header to make them available there too.
I'm *not* suggesting that we should have a modules/
Sorry to go back on my earlier approval...
Dirk Zimoch (dirk.zimoch) wrote : | # |
OK. I didn't like the code duplication either, but I wanted to keep the change minimal.
Concerning #ifdef <ARCH>, I actually like it more than separate files. Why? To avoid code duplication.
I will try to implement some macro magic...
Dirk Zimoch (dirk.zimoch) wrote : | # |
Are RTEMS/GeSys users the only ones using Cexp? If not, the functions should probably be global for everyone. How to find out if someone uses GeSys/Cexp? Should I assume this for any RTEMS and RTEMS only, thus making the functions global for vxWorks and RTEMS and static for every other OS?
Can there be a conflict with existing system functions, in particular for 'dlload' and 'echo'? Originally it was this concern why I implemented the functions for vxWorks only.
Dirk Zimoch (dirk.zimoch) wrote : | # |
Now I have
#if defined(vxWorks) || defined(__rtems__)
centrally in iocsh.h.
If preferred, I can create separate header files for vxWorks and RTEMS in osi/os/xx instead.
Andrew Johnson (anj) wrote : | # |
Cexp only exists for RTEMS, Till wrote it to replicate the functionality of the VxWorks target shell.
I'm okay with that OS-conditional being in iocsh.h, so this looks good now and I will merge it sometime in the next few days — thanks.
Preview Diff
1 | diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c | |||
2 | index cd75351..f52b888 100644 | |||
3 | --- a/modules/database/src/ioc/db/dbAccess.c | |||
4 | +++ b/modules/database/src/ioc/db/dbAccess.c | |||
5 | @@ -754,13 +754,22 @@ long dbBufferSize(short dbr_type, long options, long no_elements) | |||
6 | 754 | } | 754 | } |
7 | 755 | int dbLoadDatabase(const char *file, const char *path, const char *subs) | 755 | int dbLoadDatabase(const char *file, const char *path, const char *subs) |
8 | 756 | { | 756 | { |
9 | 757 | if (!file) { | ||
10 | 758 | printf("Usage: dbLoadDatabase \"file\", \"path\", \"subs\"\n"); | ||
11 | 759 | return -1; | ||
12 | 760 | } | ||
13 | 757 | return dbReadDatabase(&pdbbase, file, path, subs); | 761 | return dbReadDatabase(&pdbbase, file, path, subs); |
14 | 758 | } | 762 | } |
15 | 759 | 763 | ||
16 | 760 | int dbLoadRecords(const char* file, const char* subs) | 764 | int dbLoadRecords(const char* file, const char* subs) |
17 | 761 | { | 765 | { |
19 | 762 | int status = dbReadDatabase(&pdbbase, file, 0, subs); | 766 | int status; |
20 | 763 | 767 | ||
21 | 768 | if (!file) { | ||
22 | 769 | printf("Usage: dbLoadRecords \"file\", \"subs\"\n"); | ||
23 | 770 | return -1; | ||
24 | 771 | } | ||
25 | 772 | status = dbReadDatabase(&pdbbase, file, 0, subs); | ||
26 | 764 | if (!status && dbLoadRecordsHook) | 773 | if (!status && dbLoadRecordsHook) |
27 | 765 | dbLoadRecordsHook(file, subs); | 774 | dbLoadRecordsHook(file, subs); |
28 | 766 | return status; | 775 | return status; |
29 | diff --git a/modules/database/src/ioc/db/dbBkpt.c b/modules/database/src/ioc/db/dbBkpt.c | |||
30 | index 8e7bf3a..b3fdd2d 100644 | |||
31 | --- a/modules/database/src/ioc/db/dbBkpt.c | |||
32 | +++ b/modules/database/src/ioc/db/dbBkpt.c | |||
33 | @@ -283,6 +283,10 @@ long dbb(const char *record_name) | |||
34 | 283 | /* | 283 | /* |
35 | 284 | * Convert name to address | 284 | * Convert name to address |
36 | 285 | */ | 285 | */ |
37 | 286 | if (!record_name) { | ||
38 | 287 | printf("Usage: dbb \"record_name\"\n"); | ||
39 | 288 | return -1; | ||
40 | 289 | } | ||
41 | 286 | status = dbNameToAddr(record_name, &addr); | 290 | status = dbNameToAddr(record_name, &addr); |
42 | 287 | if (status == S_db_notFound) | 291 | if (status == S_db_notFound) |
43 | 288 | printf(" BKPT> Record %s not found\n", record_name); | 292 | printf(" BKPT> Record %s not found\n", record_name); |
44 | @@ -403,6 +407,10 @@ long dbd(const char *record_name) | |||
45 | 403 | /* | 407 | /* |
46 | 404 | * Convert name to address | 408 | * Convert name to address |
47 | 405 | */ | 409 | */ |
48 | 410 | if (!record_name) { | ||
49 | 411 | printf("Usage: dbd \"record_name\"\n"); | ||
50 | 412 | return -1; | ||
51 | 413 | } | ||
52 | 406 | status = dbNameToAddr(record_name, &addr); | 414 | status = dbNameToAddr(record_name, &addr); |
53 | 407 | if (status == S_db_notFound) | 415 | if (status == S_db_notFound) |
54 | 408 | printf(" BKPT> Record %s not found\n", record_name); | 416 | printf(" BKPT> Record %s not found\n", record_name); |
55 | @@ -846,6 +854,10 @@ long dbap(const char *record_name) | |||
56 | 846 | /* | 854 | /* |
57 | 847 | * Convert name to address | 855 | * Convert name to address |
58 | 848 | */ | 856 | */ |
59 | 857 | if (!record_name) { | ||
60 | 858 | printf("Usage: dbap \"record_name\"\n"); | ||
61 | 859 | return -1; | ||
62 | 860 | } | ||
63 | 849 | status = dbNameToAddr(record_name, &addr); | 861 | status = dbNameToAddr(record_name, &addr); |
64 | 850 | if (status == S_db_notFound) | 862 | if (status == S_db_notFound) |
65 | 851 | printf(" BKPT> Record %s not found\n", record_name); | 863 | printf(" BKPT> Record %s not found\n", record_name); |
66 | diff --git a/modules/database/src/ioc/db/dbNotify.c b/modules/database/src/ioc/db/dbNotify.c | |||
67 | index c718d37..c2420af 100644 | |||
68 | --- a/modules/database/src/ioc/db/dbNotify.c | |||
69 | +++ b/modules/database/src/ioc/db/dbNotify.c | |||
70 | @@ -596,9 +596,13 @@ long dbtpn(char *pname, char *pvalue) | |||
71 | 596 | tpnInfo *ptpnInfo; | 596 | tpnInfo *ptpnInfo; |
72 | 597 | processNotify *ppn=NULL; | 597 | processNotify *ppn=NULL; |
73 | 598 | 598 | ||
74 | 599 | if (!pname) { | ||
75 | 600 | printf("Usage: dbtpn \"name\", \"value\"\n"); | ||
76 | 601 | return -1; | ||
77 | 602 | } | ||
78 | 599 | chan = dbChannelCreate(pname); | 603 | chan = dbChannelCreate(pname); |
79 | 600 | if (!chan) { | 604 | if (!chan) { |
81 | 601 | printf("dbtpn: No such channel"); | 605 | printf("dbtpn: No such channel\n"); |
82 | 602 | return -1; | 606 | return -1; |
83 | 603 | } | 607 | } |
84 | 604 | 608 | ||
85 | diff --git a/modules/database/src/ioc/db/dbState.c b/modules/database/src/ioc/db/dbState.c | |||
86 | index 6de7735..60819a0 100644 | |||
87 | --- a/modules/database/src/ioc/db/dbState.c | |||
88 | +++ b/modules/database/src/ioc/db/dbState.c | |||
89 | @@ -37,6 +37,9 @@ dbStateId dbStateFind(const char *name) | |||
90 | 37 | ELLNODE *node; | 37 | ELLNODE *node; |
91 | 38 | dbStateId id; | 38 | dbStateId id; |
92 | 39 | 39 | ||
93 | 40 | if (!name) | ||
94 | 41 | return NULL; | ||
95 | 42 | |||
96 | 40 | for (node = ellFirst(&states); node; node = ellNext(node)) { | 43 | for (node = ellFirst(&states); node; node = ellNext(node)) { |
97 | 41 | id = CONTAINER(node, dbState, node); | 44 | id = CONTAINER(node, dbState, node); |
98 | 42 | if (strcmp(id->name, name) == 0) | 45 | if (strcmp(id->name, name) == 0) |
99 | @@ -49,6 +52,9 @@ dbStateId dbStateCreate(const char *name) | |||
100 | 49 | { | 52 | { |
101 | 50 | dbStateId id; | 53 | dbStateId id; |
102 | 51 | 54 | ||
103 | 55 | if (!name) | ||
104 | 56 | return NULL; | ||
105 | 57 | |||
106 | 52 | if ((id = dbStateFind(name))) | 58 | if ((id = dbStateFind(name))) |
107 | 53 | return id; | 59 | return id; |
108 | 54 | 60 | ||
109 | diff --git a/modules/database/src/ioc/db/db_test.c b/modules/database/src/ioc/db/db_test.c | |||
110 | index 8d7ad31..3d536f0 100644 | |||
111 | --- a/modules/database/src/ioc/db/db_test.c | |||
112 | +++ b/modules/database/src/ioc/db/db_test.c | |||
113 | @@ -40,6 +40,10 @@ int gft(const char *pname) | |||
114 | 40 | short type; | 40 | short type; |
115 | 41 | int i; | 41 | int i; |
116 | 42 | 42 | ||
117 | 43 | if (!pname) { | ||
118 | 44 | printf("Usage: gft \"pv_name\"\n"); | ||
119 | 45 | return -1; | ||
120 | 46 | } | ||
121 | 43 | chan = dbChannel_create(pname); | 47 | chan = dbChannel_create(pname); |
122 | 44 | if (!chan) { | 48 | if (!chan) { |
123 | 45 | printf("Channel couldn't be created\n"); | 49 | printf("Channel couldn't be created\n"); |
124 | @@ -94,6 +98,10 @@ int pft(const char *pname, const char *pvalue) | |||
125 | 94 | unsigned char charvalue; | 98 | unsigned char charvalue; |
126 | 95 | double doublevalue; | 99 | double doublevalue; |
127 | 96 | 100 | ||
128 | 101 | if (!pname || !pvalue) { | ||
129 | 102 | printf("Usage: pft \"pv_name\", \"value\"\n"); | ||
130 | 103 | return -1; | ||
131 | 104 | } | ||
132 | 97 | chan = dbChannel_create(pname); | 105 | chan = dbChannel_create(pname); |
133 | 98 | if (!chan) { | 106 | if (!chan) { |
134 | 99 | printf("Channel couldn't be created\n"); | 107 | printf("Channel couldn't be created\n"); |
135 | @@ -223,6 +231,10 @@ int tpn(const char *pname, const char *pvalue) | |||
136 | 223 | tpnInfo *ptpnInfo; | 231 | tpnInfo *ptpnInfo; |
137 | 224 | processNotify *ppn = NULL; | 232 | processNotify *ppn = NULL; |
138 | 225 | 233 | ||
139 | 234 | if (!pname || !pvalue) { | ||
140 | 235 | printf("Usage: tpn \"pv_name\", \"value\"\n"); | ||
141 | 236 | return -1; | ||
142 | 237 | } | ||
143 | 226 | chan = dbChannel_create(pname); | 238 | chan = dbChannel_create(pname); |
144 | 227 | if (!chan) { | 239 | if (!chan) { |
145 | 228 | printf("Channel couldn't be created\n"); | 240 | printf("Channel couldn't be created\n"); |
146 | diff --git a/modules/database/src/ioc/misc/dlload.c b/modules/database/src/ioc/misc/dlload.c | |||
147 | index 5b0591d..ddf04f4 100644 | |||
148 | --- a/modules/database/src/ioc/misc/dlload.c | |||
149 | +++ b/modules/database/src/ioc/misc/dlload.c | |||
150 | @@ -9,14 +9,19 @@ | |||
151 | 9 | #include "iocsh.h" | 9 | #include "iocsh.h" |
152 | 10 | #include "epicsExport.h" | 10 | #include "epicsExport.h" |
153 | 11 | 11 | ||
154 | 12 | IOCSH_STATIC_FUNC void dlload(const char* name) | ||
155 | 13 | { | ||
156 | 14 | if (!epicsLoadLibrary(name)) { | ||
157 | 15 | printf("epicsLoadLibrary failed: %s\n", epicsLoadError()); | ||
158 | 16 | } | ||
159 | 17 | } | ||
160 | 18 | |||
161 | 12 | static const iocshArg dlloadArg0 = { "path/library.so", iocshArgString}; | 19 | static const iocshArg dlloadArg0 = { "path/library.so", iocshArgString}; |
162 | 13 | static const iocshArg * const dlloadArgs[] = {&dlloadArg0}; | 20 | static const iocshArg * const dlloadArgs[] = {&dlloadArg0}; |
163 | 14 | static const iocshFuncDef dlloadFuncDef = {"dlload", 1, dlloadArgs}; | 21 | static const iocshFuncDef dlloadFuncDef = {"dlload", 1, dlloadArgs}; |
164 | 15 | static void dlloadCallFunc(const iocshArgBuf *args) | 22 | static void dlloadCallFunc(const iocshArgBuf *args) |
165 | 16 | { | 23 | { |
169 | 17 | if (!epicsLoadLibrary(args[0].sval)) { | 24 | dlload(args[0].sval); |
167 | 18 | printf("epicsLoadLibrary failed: %s\n", epicsLoadError()); | ||
168 | 19 | } | ||
170 | 20 | } | 25 | } |
171 | 21 | 26 | ||
172 | 22 | static void dlloadRegistar(void) { | 27 | static void dlloadRegistar(void) { |
173 | diff --git a/modules/libcom/src/iocsh/iocsh.h b/modules/libcom/src/iocsh/iocsh.h | |||
174 | index 3ef3d95..84b38f2 100644 | |||
175 | --- a/modules/libcom/src/iocsh/iocsh.h | |||
176 | +++ b/modules/libcom/src/iocsh/iocsh.h | |||
177 | @@ -14,8 +14,15 @@ | |||
178 | 14 | #define INCiocshH | 14 | #define INCiocshH |
179 | 15 | 15 | ||
180 | 16 | #include <stdio.h> | 16 | #include <stdio.h> |
181 | 17 | #include "compilerDependencies.h" | ||
182 | 17 | #include "shareLib.h" | 18 | #include "shareLib.h" |
183 | 18 | 19 | ||
184 | 20 | #if defined(vxWorks) || defined(__rtems__) | ||
185 | 21 | #define IOCSH_STATIC_FUNC | ||
186 | 22 | #else | ||
187 | 23 | #define IOCSH_STATIC_FUNC static EPICS_ALWAYS_INLINE | ||
188 | 24 | #endif | ||
189 | 25 | |||
190 | 19 | #ifdef __cplusplus | 26 | #ifdef __cplusplus |
191 | 20 | extern "C" { | 27 | extern "C" { |
192 | 21 | #endif | 28 | #endif |
193 | diff --git a/modules/libcom/src/iocsh/libComRegister.c b/modules/libcom/src/iocsh/libComRegister.c | |||
194 | index d3a5cfa..88abdc6 100644 | |||
195 | --- a/modules/libcom/src/iocsh/libComRegister.c | |||
196 | +++ b/modules/libcom/src/iocsh/libComRegister.c | |||
197 | @@ -27,6 +27,7 @@ | |||
198 | 27 | #include "libComRegister.h" | 27 | #include "libComRegister.h" |
199 | 28 | 28 | ||
200 | 29 | 29 | ||
201 | 30 | /* date */ | ||
202 | 30 | void date(const char *format) | 31 | void date(const char *format) |
203 | 31 | { | 32 | { |
204 | 32 | epicsTimeStamp now; | 33 | epicsTimeStamp now; |
205 | @@ -42,7 +43,6 @@ void date(const char *format) | |||
206 | 42 | puts(nowText); | 43 | puts(nowText); |
207 | 43 | } | 44 | } |
208 | 44 | 45 | ||
209 | 45 | /* date */ | ||
210 | 46 | static const iocshArg dateArg0 = { "format",iocshArgString}; | 46 | static const iocshArg dateArg0 = { "format",iocshArgString}; |
211 | 47 | static const iocshArg * const dateArgs[] = {&dateArg0}; | 47 | static const iocshArg * const dateArgs[] = {&dateArg0}; |
212 | 48 | static const iocshFuncDef dateFuncDef = {"date", 1, dateArgs}; | 48 | static const iocshFuncDef dateFuncDef = {"date", 1, dateArgs}; |
213 | @@ -52,13 +52,8 @@ static void dateCallFunc (const iocshArgBuf *args) | |||
214 | 52 | } | 52 | } |
215 | 53 | 53 | ||
216 | 54 | /* echo */ | 54 | /* echo */ |
221 | 55 | static const iocshArg echoArg0 = { "string",iocshArgString}; | 55 | IOCSH_STATIC_FUNC void echo(char* str) |
218 | 56 | static const iocshArg * const echoArgs[1] = {&echoArg0}; | ||
219 | 57 | static const iocshFuncDef echoFuncDef = {"echo",1,echoArgs}; | ||
220 | 58 | static void echoCallFunc(const iocshArgBuf *args) | ||
222 | 59 | { | 56 | { |
223 | 60 | char *str = args[0].sval; | ||
224 | 61 | |||
225 | 62 | if (str) | 57 | if (str) |
226 | 63 | dbTranslateEscape(str, str); /* in-place is safe */ | 58 | dbTranslateEscape(str, str); /* in-place is safe */ |
227 | 64 | else | 59 | else |
228 | @@ -66,6 +61,14 @@ static void echoCallFunc(const iocshArgBuf *args) | |||
229 | 66 | printf("%s\n", str); | 61 | printf("%s\n", str); |
230 | 67 | } | 62 | } |
231 | 68 | 63 | ||
232 | 64 | static const iocshArg echoArg0 = { "string",iocshArgString}; | ||
233 | 65 | static const iocshArg * const echoArgs[1] = {&echoArg0}; | ||
234 | 66 | static const iocshFuncDef echoFuncDef = {"echo",1,echoArgs}; | ||
235 | 67 | static void echoCallFunc(const iocshArgBuf *args) | ||
236 | 68 | { | ||
237 | 69 | echo(args[0].sval); | ||
238 | 70 | } | ||
239 | 71 | |||
240 | 69 | /* chdir */ | 72 | /* chdir */ |
241 | 70 | static const iocshArg chdirArg0 = { "directory name",iocshArgString}; | 73 | static const iocshArg chdirArg0 = { "directory name",iocshArgString}; |
242 | 71 | static const iocshArg * const chdirArgs[1] = {&chdirArg0}; | 74 | static const iocshArg * const chdirArgs[1] = {&chdirArg0}; |
243 | @@ -111,10 +114,15 @@ static void epicsEnvSetCallFunc(const iocshArgBuf *args) | |||
244 | 111 | } | 114 | } |
245 | 112 | 115 | ||
246 | 113 | /* epicsParamShow */ | 116 | /* epicsParamShow */ |
247 | 117 | IOCSH_STATIC_FUNC void epicsParamShow() | ||
248 | 118 | { | ||
249 | 119 | epicsPrtEnvParams (); | ||
250 | 120 | } | ||
251 | 121 | |||
252 | 114 | static const iocshFuncDef epicsParamShowFuncDef = {"epicsParamShow",0,NULL}; | 122 | static const iocshFuncDef epicsParamShowFuncDef = {"epicsParamShow",0,NULL}; |
253 | 115 | static void epicsParamShowCallFunc(const iocshArgBuf *args) | 123 | static void epicsParamShowCallFunc(const iocshArgBuf *args) |
254 | 116 | { | 124 | { |
256 | 117 | epicsPrtEnvParams (); | 125 | epicsParamShow (); |
257 | 118 | } | 126 | } |
258 | 119 | 127 | ||
259 | 120 | /* epicsPrtEnvParams */ | 128 | /* epicsPrtEnvParams */ |
260 | @@ -148,12 +156,17 @@ static void iocLogInitCallFunc(const iocshArgBuf *args) | |||
261 | 148 | } | 156 | } |
262 | 149 | 157 | ||
263 | 150 | /* iocLogDisable */ | 158 | /* iocLogDisable */ |
264 | 159 | IOCSH_STATIC_FUNC void setIocLogDisable(int val) | ||
265 | 160 | { | ||
266 | 161 | iocLogDisable = val; | ||
267 | 162 | } | ||
268 | 163 | |||
269 | 151 | static const iocshArg iocLogDisableArg0 = {"(0,1)=>(false,true)",iocshArgInt}; | 164 | static const iocshArg iocLogDisableArg0 = {"(0,1)=>(false,true)",iocshArgInt}; |
270 | 152 | static const iocshArg * const iocLogDisableArgs[1] = {&iocLogDisableArg0}; | 165 | static const iocshArg * const iocLogDisableArgs[1] = {&iocLogDisableArg0}; |
271 | 153 | static const iocshFuncDef iocLogDisableFuncDef = {"setIocLogDisable",1,iocLogDisableArgs}; | 166 | static const iocshFuncDef iocLogDisableFuncDef = {"setIocLogDisable",1,iocLogDisableArgs}; |
272 | 154 | static void iocLogDisableCallFunc(const iocshArgBuf *args) | 167 | static void iocLogDisableCallFunc(const iocshArgBuf *args) |
273 | 155 | { | 168 | { |
275 | 156 | iocLogDisable = args[0].ival; | 169 | setIocLogDisable(args[0].ival); |
276 | 157 | } | 170 | } |
277 | 158 | 171 | ||
278 | 159 | /* iocLogShow */ | 172 | /* iocLogShow */ |
279 | @@ -197,12 +210,17 @@ static void errlogInit2CallFunc(const iocshArgBuf *args) | |||
280 | 197 | } | 210 | } |
281 | 198 | 211 | ||
282 | 199 | /* errlog */ | 212 | /* errlog */ |
283 | 213 | IOCSH_STATIC_FUNC void errlog(const char *message) | ||
284 | 214 | { | ||
285 | 215 | errlogPrintfNoConsole("%s\n", message); | ||
286 | 216 | } | ||
287 | 217 | |||
288 | 200 | static const iocshArg errlogArg0 = { "message",iocshArgString}; | 218 | static const iocshArg errlogArg0 = { "message",iocshArgString}; |
289 | 201 | static const iocshArg * const errlogArgs[1] = {&errlogArg0}; | 219 | static const iocshArg * const errlogArgs[1] = {&errlogArg0}; |
290 | 202 | static const iocshFuncDef errlogFuncDef = {"errlog",1,errlogArgs}; | 220 | static const iocshFuncDef errlogFuncDef = {"errlog",1,errlogArgs}; |
291 | 203 | static void errlogCallFunc(const iocshArgBuf *args) | 221 | static void errlogCallFunc(const iocshArgBuf *args) |
292 | 204 | { | 222 | { |
294 | 205 | errlogPrintfNoConsole("%s\n", args[0].sval); | 223 | errlog(args[0].sval); |
295 | 206 | } | 224 | } |
296 | 207 | 225 | ||
297 | 208 | /* iocLogPrefix */ | 226 | /* iocLogPrefix */ |
298 | diff --git a/modules/libcom/src/osi/os/Darwin/osdEnv.c b/modules/libcom/src/osi/os/Darwin/osdEnv.c | |||
299 | index ab3f936..e6206c3 100644 | |||
300 | --- a/modules/libcom/src/osi/os/Darwin/osdEnv.c | |||
301 | +++ b/modules/libcom/src/osi/os/Darwin/osdEnv.c | |||
302 | @@ -35,6 +35,7 @@ | |||
303 | 35 | */ | 35 | */ |
304 | 36 | epicsShareFunc void epicsShareAPI epicsEnvSet (const char *name, const char *value) | 36 | epicsShareFunc void epicsShareAPI epicsEnvSet (const char *name, const char *value) |
305 | 37 | { | 37 | { |
306 | 38 | if (!name) return; | ||
307 | 38 | iocshEnvClear(name); | 39 | iocshEnvClear(name); |
308 | 39 | setenv(name, value, 1); | 40 | setenv(name, value, 1); |
309 | 40 | } | 41 | } |
310 | diff --git a/modules/libcom/src/osi/os/default/osdEnv.c b/modules/libcom/src/osi/os/default/osdEnv.c | |||
311 | index 682bcc9..b284a86 100644 | |||
312 | --- a/modules/libcom/src/osi/os/default/osdEnv.c | |||
313 | +++ b/modules/libcom/src/osi/os/default/osdEnv.c | |||
314 | @@ -36,6 +36,7 @@ epicsShareFunc void epicsShareAPI epicsEnvSet (const char *name, const char *val | |||
315 | 36 | { | 36 | { |
316 | 37 | char *cp; | 37 | char *cp; |
317 | 38 | 38 | ||
318 | 39 | if (!name) return; | ||
319 | 39 | iocshEnvClear(name); | 40 | iocshEnvClear(name); |
320 | 40 | 41 | ||
321 | 41 | cp = mallocMustSucceed (strlen (name) + strlen (value) + 2, "epicsEnvSet"); | 42 | cp = mallocMustSucceed (strlen (name) + strlen (value) + 2, "epicsEnvSet"); |
322 | diff --git a/modules/libcom/src/osi/os/iOS/osdEnv.c b/modules/libcom/src/osi/os/iOS/osdEnv.c | |||
323 | index a32cce5..fdc4570 100644 | |||
324 | --- a/modules/libcom/src/osi/os/iOS/osdEnv.c | |||
325 | +++ b/modules/libcom/src/osi/os/iOS/osdEnv.c | |||
326 | @@ -32,6 +32,7 @@ | |||
327 | 32 | */ | 32 | */ |
328 | 33 | epicsShareFunc void epicsShareAPI epicsEnvSet (const char *name, const char *value) | 33 | epicsShareFunc void epicsShareAPI epicsEnvSet (const char *name, const char *value) |
329 | 34 | { | 34 | { |
330 | 35 | if (!name) return; | ||
331 | 35 | iocshEnvClear(name); | 36 | iocshEnvClear(name); |
332 | 36 | setenv(name, value, 1); | 37 | setenv(name, value, 1); |
333 | 37 | } | 38 | } |
334 | diff --git a/modules/libcom/src/osi/os/vxWorks/osdEnv.c b/modules/libcom/src/osi/os/vxWorks/osdEnv.c | |||
335 | index c81f493..9245ae7 100644 | |||
336 | --- a/modules/libcom/src/osi/os/vxWorks/osdEnv.c | |||
337 | +++ b/modules/libcom/src/osi/os/vxWorks/osdEnv.c | |||
338 | @@ -37,6 +37,11 @@ epicsShareFunc void epicsShareAPI epicsEnvSet (const char *name, const char *val | |||
339 | 37 | { | 37 | { |
340 | 38 | char *cp; | 38 | char *cp; |
341 | 39 | 39 | ||
342 | 40 | if (!name) { | ||
343 | 41 | printf ("Usage: epicsEnvSet \"name\", \"value\"\n"); | ||
344 | 42 | return; | ||
345 | 43 | } | ||
346 | 44 | |||
347 | 40 | iocshEnvClear(name); | 45 | iocshEnvClear(name); |
348 | 41 | 46 | ||
349 | 42 | cp = mallocMustSucceed (strlen (name) + strlen (value) + 2, "epicsEnvSet"); | 47 | cp = mallocMustSucceed (strlen (name) + strlen (value) + 2, "epicsEnvSet"); |
Hi Dirk,
Good idea, a few comments about your specific changes though.
It's only the VxWorks shell (and I guess the RTEMS CEXP shell) that can pass in NULL pointers to some of these commands. Adding the NULL check to any osdEnv.c file except for libcom/ src/osi/ os/vxWorks/ osdEnv. c doesn't make too much sense to me.
I would prefer that we not print anything in dbStateCreate() which is also an API entry point for the dbState subsystem, just return NULL for a NULL input.
Your VxWorks dlload() routine needs a check for a NULL input argument...
Finally a few comments about your Usage messages: Parentheses are not required around arguments to VxWorks or iocsh commands, they're only needed for an IOC using CEXP on RTEMS, and the people who run such IOCs know about the requirement. Parentheses take longer to type and I'd rather we not imply they're needed when they aren't. The iocsh help output shows command usage without parentheses (which are allowed there too), although I wish it prefixed the full command with "Usage:" when shown with argumemts (like you do):
epics> help dbLoadDatabase
dbLoadDatabase 'file name' path substitutions
epics> help dbLoadRecords
dbLoadRecords 'file name' substitutions
epics> help dbb
dbb 'record name'
epics> help dbtpn
dbtpn 'record name' value
epics> help epicsEnvSet
epicsEnvSet name value
That help command only puts quotes around arguments that have spaces in their name, which is different than the requirements of the VxWorks shell (but that is how the iocsh parses arguments). Your use of double-quotes around string arguments shows they are required for VxWorks though, which is fine and correct.
Thanks,
- Andrew