Merge lp:~mdavidsaver/epics-base/epicsconf into lp:~epics-core/epics-base/3.14

Proposed by mdavidsaver
Status: Rejected
Rejected by: Andrew Johnson
Proposed branch: lp:~mdavidsaver/epics-base/epicsconf
Merge into: lp:~epics-core/epics-base/3.14
Diff against target: 517 lines (+278/-22)
12 files modified
epics.conf (+72/-0)
src/libCom/Makefile (+7/-0)
src/libCom/env/envDefs.h (+1/-0)
src/libCom/env/fileLoad.cpp (+128/-0)
src/libCom/iocsh/iocsh.cpp (+14/-7)
src/libCom/iocsh/iocsh.h (+1/-0)
src/libCom/iocsh/libComRegister.c (+20/-0)
src/libCom/macLib/macCore.c (+8/-15)
src/libCom/macLib/macLib.h (+6/-0)
src/libCom/osi/os/Darwin/osdEnv.c (+7/-0)
src/libCom/osi/os/default/osdEnv.c (+7/-0)
src/libCom/osi/os/vxWorks/osdEnv.c (+7/-0)
To merge this branch: bzr merge lp:~mdavidsaver/epics-base/epicsconf
Reviewer Review Type Date Requested Status
Andrew Johnson Disapprove
Ralph Lange Pending
EPICS Core Developers Pending
Review via email: mp+23106@code.launchpad.net

Commit message

Allow some setting currently set as environment variables to be given in a config file. This is intended for CA clients as a way to specify EPICS_CA_ADDR_LIST system-wide (i.e. /etc/epics.conf). Follows the usual order of precedence with individual environment variables first to preserve the current behavior.

Description of the change

Allow some setting currently set as environment variables to be given in a config file. This is intended for CA clients as a way to specify EPICS_CA_ADDR_LIST system-wide (i.e. /etc/epics.conf). Follows the usual order of precedence with individual environment variables first to preserve the current behavior.

Revision one is limited in scope. It effects only those environment variables defined in 'src/libCom/env/envDefs.h'. It is also completely self-contained. It runs once at load-time and uses the values it reads to set the unset environment variables.

A sample config file is included with all options commented out.

Initially added only for linux. Adding for other systems is as simple as linking in one additional object.

To post a comment you must log in.
Revision history for this message
Andrew Johnson (anj) wrote :

Firstly, please convince me why this is necessary? A package can set environment variables on most on Linux distributions by adding files to /etc/profile.d and users can override them in ~/.login ~/.cshrc or ~/.profile as they wish. IOC startup scripts may contain epicsEnvSet commands. Why do we need yet another way to set environment variables?

If we do provide this facility, people are going to want to use it on all IOC architectures, so implementing it on just one OS is not a good idea. I accept that it was designed for Linux, but I know that someone like Ernest Williams is going to want to use it on vxWorks or RTEMS if we don't provide it in the initial release.

The current code is not portable to vxWorks. The setenv() routine is not available there, use epicsEnvSet() or putenv() instead.

We also have problems using C++ STL containers on vxWorks. No other code in the IOC uses them because STL containers create and destroy objects a lot, which used to cause major memory fragmentation in the vxWorks memory allocator; not sure if it still does, although that shouldn't be a problem with this code. However since the IOC hasn't needed it before and memory is precious on embedded systems, most sites don't build the STL support package into their vxWorks OS images, and for a minor change this will cause major pain. I got lots of very ugly "undefined symbol" errors for internal STL routines when I tried to load the fileLoad.o file on one of my boards here. Note also that as written the vxWorks linker does not include this file in the executable it generates, since no symbols reference it; that's why I had to explicitly load the fileLoad.o object by hand.

The list of files to load should not be hard-coded in the source to fileLoad.cpp. Define a new parameter called EPICS_CONFIG_PATH which is set in base/configure/CONFIG_ENV and read using an envGetConfigParam*() routine. Its value probably needs to be architecture-specific though and we don't currently have a mechanism to set default values from an arch-specific file, so bldEnvData.pl needs to be changed to handle that and some architecture-specific files added.

How to specify multiple files in one parameter? Use OSI_PATH_LIST_SEPARATOR from osiFileName.h so the value looks like that of a regular ...PATH environment variable except it points to files, not directories.

review: Disapprove
Revision history for this message
Ralph Lange (ralph-lange) wrote :

I don't think this is intended for target systems at all - it's a client-only issue.

Which would be an answer to the vxWorks/RTEMS/STL/IOC/vxWorks-linker issues that Andrew mentioned.

Revision history for this message
mdavidsaver (mdavidsaver) wrote :
Download full text (3.6 KiB)

> Firstly, please convince me why this is necessary? A package can set
> environment variables on most on Linux distributions by adding files to
> /etc/profile.d and users can override them in ~/.login ~/.cshrc or ~/.profile
> as they wish.

Which shell (sh, csh)? Environment variables are a poor way to do configuration.

> IOC startup scripts may contain epicsEnvSet commands. Why do
> we need yet another way to set environment variables?

For IOCs you don't. This is for EDM, ALH, channel archiver, and my python scripts. Client applications which run on something other then vxworks or rtems.

The intent is to allow libca to be configured in the way that almost all other applications/libraries are.

>
> If we do provide this facility, people are going to want to use it on all IOC
> architectures, so implementing it on just one OS is not a good idea. I accept
> that it was designed for Linux, but I know that someone like Ernest Williams
> is going to want to use it on vxWorks or RTEMS if we don't provide it in the
> initial release.

I don't see any reason to use it work on an embedded system. There it gives no benefit over epicsEnvSet and IOC configuration would require yet another file.

> The current code is not portable to vxWorks. The setenv() routine is not
> available there, use epicsEnvSet() or putenv() instead.

Ah, I will do this.

> We also have problems using C++ STL containers on vxWorks. No other code in
> the IOC uses them because STL containers create and destroy objects a lot,
> which used to cause major memory fragmentation in the vxWorks memory
> allocator; not sure if it still does, although that shouldn't be a problem
> with this code. However since the IOC hasn't needed it before and memory is
> precious on embedded systems, most sites don't build the STL support package
> into their vxWorks OS images, and for a minor change this will cause major
> pain. I got lots of very ugly "undefined symbol" errors for internal STL
> routines when I tried to load the fileLoad.o file on one of my boards here.
> Note also that as written the vxWorks linker does not include this file in the
> executable it generates, since no symbols reference it; that's why I had to
> explicitly load the fileLoad.o object by hand.

So maybe this should be host only...

>
> The list of files to load should not be hard-coded in the source to
> fileLoad.cpp.

Configuration files don't work unless people know where they are. Uniformity is important. It should follow the conventions of the host OS. Currently fileLoad just has the *nix set. A set of paths for Windows is also needed.

> Define a new parameter called EPICS_CONFIG_PATH which is set in
> base/configure/CONFIG_ENV and read using an envGetConfigParam*() routine. Its
> value probably needs to be architecture-specific though and we don't currently
> have a mechanism to set default values from an arch-specific file, so
> bldEnvData.pl needs to be changed to handle that and some architecture-
> specific files added.

#ifdef I_don_t_have_a_better_answer_then_

> How to specify multiple files in one parameter? Use OSI_PATH_LIST_SEPARATOR
> from osiFileName.h so the value looks like t...

Read more...

Revision history for this message
Andrew Johnson (anj) wrote :
Download full text (3.6 KiB)

The Art of Unix Programming talks about application configuration here:
    http://www.faqs.org/docs/artu/configurationchapter.html
In particular, http://www.faqs.org/docs/artu/ch10s04.html#id2942882 says that environment variables are useful when:
 * A value varies across several contexts that share dotfiles,
 * A value varies too often for dotfiles, but doesn't change on every startup
Both of those definitely apply to Channel Access client programs, so I don't see myself as being the only person to disagree with your blanket statement "Environment variables are a poor way to do configuration."

I agree that it is not necessary to implement this feature for IOCs, but as written all Linux IOCs /will/ attempt to read those files while IOCs on other architectures would not; this will cause user confusion, so at minimum all workstation architectures would need to support this (at the APS we have soft IOCs that we can run on Linux, Darwin or Solaris as needed). Unlike the access security and dbStatic subsystems we don't have separate versions of libCom for Host vs. IOC programs, so we're stuck with only being able to distinguish by target architecture.

I think we should implement this for all architectures, but make the list of files to read be configurable from a file in base/configure/, and since we already have a mechanism that does some of the work we should modify that to implement the solution. Here's how I think this should work:

1. Modify base/src/libCom/env/bldEnvData.pl and any necessary build rules to read the optional files CONFIG_ENV.$(T_A) and CONFIG_SITE_ENV.$(T_A) from base/configure when generating the envData.c files in libCom/O.$(T_A). Obviously the architecture-specific files should override (i.e. be read after) the generic ones. This gives base and our sites the ability to specify architecture-specific defaults to the existing environment parameters.
2. Add a new enviroment parameter named something like EPICS_CONFIG_PATH or EPICS_RC_FILES that lists the config files to be read. You don't have to allow the environment variable to override the compiled-in value if you don't want to, although I don't see the point of preventing an override if a user has some need to do that (I personally hope to never need to set LD_PRELOAD, but I like that it's there if I do). The default value for this parameter will be given in an architecture-specific base/configure file as described above, so that on vxWorks and RTEMS it would be blank, and Windows can have a different setting than the Unix-like OSs.
3. The file parser should be integrated into base/src/libCom/env/envSubr.c (not using STL, although I don't object to C++ if you prefer it), and it should only accept settings which are known parameters. It reads the files in order and overrides the compiled-in pParam->pdflt strings with the values from the config files (this will need changes to envDefs.h to move the const).

Doing it this way any environment variables will still override but can be distinguished from the values read from the files. File settings don't pollute the environment variables, nor do we permit users to add other settings to the files which are not EPICS pa...

Read more...

lp:~mdavidsaver/epics-base/epicsconf updated
12046. By mdavidsaver

IOCsh: create a version of iocsh() which can be quiet

12047. By mdavidsaver

env: add epicsEnvSetIfUnset

12048. By mdavidsaver

macLib: expose use environment flag

12049. By mdavidsaver

use iocsh to parse config file

Use macLib to expand strings w/ environment variables
Use Base build path is search path ($(EPICS_BASE)/epics.conf)
Add search path for win32
Exclude from builds for RTEMS/vxWorks targets

12050. By mdavidsaver

update config file syntax

Revision history for this message
mdavidsaver (mdavidsaver) wrote :

First the changes, then the questions

Removes the file parser and replaces it with iocsh(). Creates a modified version (iocsh2()) which has an additional option to control output to console. The default when invoked through fileLoad is silence.

Adds the command epicsEnvSetIfUnset to the ioc shell. Behaves like epicsEnvSet if the variable named has not previously been set. If it has then it is not modified.

The file list remains "static". However, it is defined in terms of some macLib style macros. macLib is made to use environment variables when expanding these macros. Additions made for windows.

Revision history for this message
mdavidsaver (mdavidsaver) wrote :
Download full text (4.1 KiB)

> The Art of Unix Programming talks about application configuration here:
> http://www.faqs.org/docs/artu/configurationchapter.html
> In particular, http://www.faqs.org/docs/artu/ch10s04.html#id2942882 says that
> environment variables are useful when:
> * A value varies across several contexts that share dotfiles,

An example? Most of these parameters are system wide. The only ones I see which don't follow this rule are the PORT options. In that case I would suggest creating an alternate config file and using EPICS_SYS_CONFIG=filename.

> * A value varies too often for dotfiles, but doesn't change on every startup

The examples I see in this category are IOC specific and shouldn't be set it any shared config file.

If you look in TAUp a little way down in the "When to Use Environment Variables" section you will see the following.

"There is one traditional Unix design pattern that we do not recommend for new programs. Sometimes, user-set environment variables are used as a lightweight substitute for expressing a program preference in a run-control file."

This is more or less exactly how I would describe the problem with EPICS and related client programs. Base understands 26 environment variables. And if you consider clients like EDM (34) this number goes up rapidly.

> Both of those definitely apply to Channel Access client programs, so I don't
> see myself as being the only person to disagree with your blanket statement
> "Environment variables are a poor way to do configuration."

So perhaps I should say: 60 environment variables are a poor way to do configuration.

> I agree that it is not necessary to implement this feature for IOCs, but as
> written all Linux IOCs /will/ attempt to read those files while IOCs on other
> architectures would not; this will cause user confusion, so at minimum all
> workstation architectures would need to support this (at the APS we have soft
> IOCs that we can run on Linux, Darwin or Solaris as needed). Unlike the
> access security and dbStatic subsystems we don't have separate versions of
> libCom for Host vs. IOC programs, so we're stuck with only being able to
> distinguish by target architecture.

Maybe we should have two versions of libca: libcaIoc which excludes fileLoad and other "client only" bits. and libca which excludes and "IOC only" bits.

I am also thinking about how to do a runtime test to find out if the process is an IOC.

>
> I think we should implement this for all architectures, but make the list of
> files to read be configurable from a file in base/configure/, and since we
> already have a mechanism that does some of the work we should modify that to
> implement the solution.

Honestly, before I embarked on this I would make the search path fully configurable at runtime.

> Here's how I think this should work:
> [...]
>
> Doing it this way any environment variables will still override but can be
> distinguished from the values read from the files. File settings don't
> pollute the environment variables, nor do we permit users to add other
> settings to the files which are not EPICS parameters. The epicsPrtEnvParams()
> routine displays the current parameters while e...

Read more...

Revision history for this message
Andrew Johnson (anj) wrote :
Download full text (4.8 KiB)

I don't believe a iocsh new command would be necessary, one can currently use
    epicsEnvSet VAR "$(VAR=new value)"
to set VAR to "new value" only if it is not currently set.

The idea of using iocsh to parse the config file(s) is ingenious. However this solution is starting to feel rather kludgey (the config file syntax gets ugly), and it doesn't take into account that iocsh doesn't always have the same commands registered. If I create a stand-alone sequence program and ask it to bring up an iocsh, it doesn't currently know epicsEnvSet or any of the other libCom commands:
  octo% bin/linux-x86_64/sncProgram -s
  SEQ Version 2.0.12: Wed Apr 28 10:54:19 2010
  Spawning state program "sncExample", thread 0x8f5bc20: "sncExample"
  epics> help
  Type `help command_name' to get more information about a particular command.
  # ClockTime_Report exit help
  iocshCmd seq seqChanShow seqQueueShow seqShow
  seqStop seqcar
  epics>
A sequence program is a stand-alone CA client so would read the config files but would not be able to understand the commands in them. To fix that we'd have to change how we register the libCom commands with the IOC shell, thus the changes needed get bigger and more invasive.

I really don't like the architecture-specific code in fileLoad.cpp. We have worked hard to keep architecture-specific code almost exclusively to the libCom/osi/os/* directories, and I don't think we should change that policy here. This was why I suggested in a previous comment to should use an environment parameter for the list of config files; it is then a relatively small change to make that list empty by default on vxWorks and RTEMS.

I don't believe your stringification of the EPICS_BASE macro will work on Windows, where a back-slash is used for the directory separator. I had major difficulties with this in src/softIoc until I used Perl to create the epicsInstallDir.h file. If you need to know the value of $(INSTALL_DIR) we should move the creation of the epicsInstallDir.h file into libCom. Where does $(PWD) get its value from anyway? INSTALL_DIR != TOP at some sites.

Why do you want to break macLib's encapsulation? A MAC_HANDLE is supposed to be opaque to its customers; admittedly the method is not documented in the appDevGuide but macEnv.c shows how to create a handle with FLAG_USE_ENVIRONMENT set, and macSuppressWarning() lets you set FLAG_SUPPRESS_WARNINGS.

There are a number of Code Smells in this branch currently. I'm not saying Base isn't already smelly, but new code should make things better if possible, and never worse.

Now replies to some of Michael's comments:

> > environment variables are useful when:
> > * A value varies across several contexts that share dotfiles,
>
> An example? Most of these parameters are system wide. The only ones I see
> which don't follow this rule are the PORT options. In that case I would
> suggest creating an alternate config file and using EPICS_SYS_CONFIG=filename.
>
> > * A value varies too often for dotfiles, but doesn't change on every
> > startup
>
> The examples I see in this category are IOC specific and shou...

Read more...

Unmerged revisions

12050. By mdavidsaver

update config file syntax

12049. By mdavidsaver

use iocsh to parse config file

Use macLib to expand strings w/ environment variables
Use Base build path is search path ($(EPICS_BASE)/epics.conf)
Add search path for win32
Exclude from builds for RTEMS/vxWorks targets

12048. By mdavidsaver

macLib: expose use environment flag

12047. By mdavidsaver

env: add epicsEnvSetIfUnset

12046. By mdavidsaver

IOCsh: create a version of iocsh() which can be quiet

12045. By mdavidsaver

set env. config from a file

On startup read key/value pairs from a set list
of files and use these to set any unset Base
environment variables.

While this will work for softiocs it is really
intended for CA clients

Files will include lines like

EPICS_CA_ADDR_LIST = "localhost 192.168.1.1"

allows comments
handles ~/ correctly

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'epics.conf'
2--- epics.conf 1970-01-01 00:00:00 +0000
3+++ epics.conf 2010-04-26 19:21:32 +0000
4@@ -0,0 +1,72 @@
5+
6+## The following parameters apply to all Channel Access
7+## clients (including IOCs).
8+
9+# The list of interfaces and IPs the CA clients should
10+# use when attempting to connect before using the
11+# automatic list.
12+#
13+# A space seperated list of IP addresses
14+# (XXX.XXX.XXX.XXX) and network addresses
15+# (YYY.YYY.YYY.YYY:PP). Hostname may be used.
16+#
17+# ie EPICS_CA_ADDR_LIST="localhost myioc.local 192.168.1.0:24"
18+#
19+#epicsEnvSetIfUnset("EPICS_CA_ADDR_LIST","")
20+
21+# Include all local interfaces (including localhost)
22+# in the connection list.
23+#epicsEnvSetIfUnset("EPICS_CA_AUTO_ADDR_LIST","YES")
24+
25+# The maximum array size which can be handled by
26+# a client.
27+#epicsEnvSetIfUnset("EPICS_CA_MAX_ARRAY_BYTES","16384")
28+
29+# Timeout in seconds before a server is declared to
30+# be unreachable and the client will start the reconnection
31+# process.
32+#epicsEnvSetIfUnset("EPICS_CA_CONN_TMO","30.0")
33+
34+#epicsEnvSetIfUnset("EPICS_CA_BEACON_PERIOD","15.0")
35+#epicsEnvSetIfUnset("EPICS_CA_MAX_SEARCH_PERIOD","300")
36+
37+# The port on which clients (repeater) and servers
38+# operate.
39+#epicsEnvSetIfUnset("EPICS_CA_REPEATER_PORT","5065")
40+#epicsEnvSetIfUnset("EPICS_CA_SERVER_PORT","5064")
41+
42+## These parameters apply only to IOCs
43+
44+# Name/IP for NTP server for IOCs
45+#epicsEnvSetIfUnset("EPICS_TS_NTP_INET","")
46+
47+# IOC shell prompt
48+#epicsEnvSetIfUnset("IOCSH_PS1","epics> ")
49+
50+# IOC shell history buffer size
51+#epicsEnvSetIfUnset("IOCSH_HISTSIZE","50")
52+
53+#epicsEnvSetIfUnset("EPICS_IOC_LOG_PORT","7004")
54+#epicsEnvSetIfUnset("EPICS_IOC_LOG_INET","")
55+#epicsEnvSetIfUnset("EPICS_IOC_LOG_FILE_LIMIT","1000000")
56+#epicsEnvSetIfUnset("EPICS_IOC_LOG_FILE_NAME","")
57+#epicsEnvSetIfUnset("EPICS_IOC_LOG_FILE_COMMAND","")
58+
59+## The following apply to the portable channel
60+## access server, but NOT to IOCs.
61+
62+#epicsEnvSetIfUnset("EPICS_CAS_INTF_ADDR_LIST","")
63+#epicsEnvSetIfUnset("EPICS_CAS_IGNORE_ADDR_LIST","")
64+#epicsEnvSetIfUnset("EPICS_CAS_AUTO_BEACON_ADDR_LIST","")
65+#epicsEnvSetIfUnset("EPICS_CAS_BEACON_ADDR_LIST","")
66+#epicsEnvSetIfUnset("EPICS_CAS_SERVER_PORT","")
67+#epicsEnvSetIfUnset("EPICS_CAS_BEACON_PERIOD","")
68+#epicsEnvSetIfUnset("EPICS_CAS_BEACON_PORT","")
69+
70+## The remaining parameters do not have any effect
71+## on EPICS Base, but may be used by some other
72+## applications.
73+
74+#epicsEnvSetIfUnset("EPICS_TIMEZONE","CUS::360:031402:110702")
75+#epicsEnvSetIfUnset("EPICS_CMD_PROTO_PORT","")
76+#epicsEnvSetIfUnset("EPICS_AR_PORT","7002")
77
78=== modified file 'src/libCom/Makefile'
79--- src/libCom/Makefile 2009-04-02 21:15:26 +0000
80+++ src/libCom/Makefile 2010-04-26 19:21:32 +0000
81@@ -75,6 +75,13 @@
82 INC += envDefs.h
83 SRCS += envSubr.c
84 SRCS += envData.c
85+SRCS += fileLoad.cpp
86+
87+ifeq ($(GNU)$(OS_CLASS),NOWIN32)
88+fileLoad_CPPFLAGS += "/DEPICS_BASE:$(PWD)\"
89+else
90+fileLoad_CPPFLAGS += -DEPICS_BASE="$(PWD)/"
91+endif
92
93 SRC_DIRS += $(LIBCOM)/error
94 INC += epicsPrint.h
95
96=== modified file 'src/libCom/env/envDefs.h'
97--- src/libCom/env/envDefs.h 2009-06-05 19:56:33 +0000
98+++ src/libCom/env/envDefs.h 2010-04-26 19:21:32 +0000
99@@ -89,6 +89,7 @@
100 (const ENV_PARAM *pEnv, unsigned short defaultPort);
101 epicsShareFunc long epicsShareAPI epicsPrtEnvParams(void);
102 epicsShareFunc void epicsShareAPI epicsEnvSet (const char *name, const char *value);
103+epicsShareFunc void epicsShareAPI epicsEnvSetIfUnset (const char *name, const char *value);
104 epicsShareFunc void epicsShareAPI epicsEnvShow (const char *name);
105
106 #ifdef __cplusplus
107
108=== added file 'src/libCom/env/fileLoad.cpp'
109--- src/libCom/env/fileLoad.cpp 1970-01-01 00:00:00 +0000
110+++ src/libCom/env/fileLoad.cpp 2010-04-26 19:21:32 +0000
111@@ -0,0 +1,128 @@
112+/* Michael Davidsaver <mdavidsaver@bnl.gov>
113+ * Brookhaven National Lab
114+ * April 2010
115+ */
116+
117+/* Configuration file loader for CA clients and
118+ * software IOCs. Configuration in this case
119+ * is an IOCshell script with a reduced set of
120+ * commends (libCom only). The most common
121+ * use will be "epicsEnvSetIfUnset(name,value)"
122+ *
123+ * This isn't really useful of IOCs since it is
124+ * exactly equivalent to
125+ *
126+ * < /some/place/epics.conf
127+ * < /some/other/place/epics.conf
128+ *
129+ * only the paths are hardcoded. However,
130+ * the lack of a CA client-only library
131+ * means that it can't be excluded from
132+ * softiocs.
133+ */
134+#if !defined(vxWorks) && !defined(__rtems__)
135+
136+#include <cstdio>
137+
138+#include "epicsStdlib.h"
139+#include "envDefs.h"
140+#include "macLib.h"
141+#include "iocsh.h"
142+#include "libComRegister.h"
143+
144+#define STRINGIFY2(X) #X
145+#define STRINGIFY(X) STRINGIFY2(X)
146+
147+// List of files to load
148+static const char* const sources[]=
149+{
150+ "${EPICS_CONFIG}" // remember that macLib is recursive
151+ ,"epics.conf"
152+#if defined(__unix) || defined(__unix__)
153+ ,"${HOME}/.epics.conf"
154+#elif defined(_WIN32)
155+ ,"${USERPROFILE}\epics.conf"
156+ /* C:\Documents and Settings\username\epics.conf on XP
157+ * C:\Users\username\epics.conf on Vista and WIN7
158+ */
159+#endif
160+ ,"${EPICS_SYS_CONFIG}"
161+#if defined(EPICS_BASE)
162+ ,STRINGIFY(EPICS_BASE) "epics.conf"
163+#endif
164+#if defined(__unix) || defined(__unix__)
165+ ,"/etc/epics.conf"
166+#elif defined(_WIN32)
167+ ,"${ALLUSERSPROFILE}\epics.conf"
168+ /* C:\Documents and Settings\All Users\epics.conf on XP
169+ * C:\ProgramData\epics.conf on Vista and WIN7
170+ */
171+#endif
172+ ,0
173+};
174+
175+static char *envpairs[]={ NULL, NULL};
176+
177+static void load()
178+{
179+ MAC_HANDLE *vars=0;
180+ int verb=0;
181+ unsigned long maxstr=256;
182+ long len;
183+ char *out;
184+
185+ if (getenv("EPICS_VERBOSE"))
186+ verb=1;
187+
188+ out=(char*)malloc(maxstr);
189+ if (!out
190+ || macCreateHandle(&vars, envpairs)
191+#if defined(EPICS_BASE)
192+ || macPutValue(vars, "EPICS_BASE", STRINGIFY(EPICS_BASE))<0
193+#endif
194+ )
195+ {
196+ fprintf(stderr, "out of memory while loading config environment");
197+ }
198+ vars->flags |= MAC_FLAG_USE_ENVIRONMENT;
199+ if (!verb)
200+ vars->flags |= MAC_FLAG_SUPPRESS_WARNINGS;
201+
202+ // A redudent call to ensure that all needed
203+ // IOC shell commands are available
204+ libComRegister();
205+
206+ // Populate from files
207+ for(size_t i=0; sources[i]; i++) {
208+ len=macExpandString(vars, sources[i], out, maxstr);
209+ if (len<0) {
210+ if (verb) fprintf(stderr, "Error expanding %s\n",sources[i]);
211+ continue;
212+ } else if(len==0) {
213+ if (verb) fprintf(stderr, "Expanding %s yields a null string\n",sources[i]);
214+ continue;
215+ }
216+
217+ if (verb) fprintf(stderr, "Loading config from %s (%s)\n", sources[i], out);
218+ iocsh2(out, verb);
219+ }
220+
221+ free(out);
222+ macDeleteHandle(vars);
223+
224+}
225+
226+class EpicsFileLoader {
227+public:
228+ EpicsFileLoader() {
229+ load();
230+ }
231+};
232+
233+#if !defined(__GNUC__) || !(__GNUC__<2 || (__GNUC__==2 && __GNUC_MINOR__<=95))
234+namespace { EpicsFileLoader epicsFileLoader; }
235+#else
236+EpicsFileLoader epicsFileLoader;
237+#endif
238+
239+#endif // !defined(vxWorks) && !defined(__rtems__)
240
241=== modified file 'src/libCom/iocsh/iocsh.cpp'
242--- src/libCom/iocsh/iocsh.cpp 2008-07-29 21:11:56 +0000
243+++ src/libCom/iocsh/iocsh.cpp 2010-04-26 19:21:32 +0000
244@@ -457,7 +457,7 @@
245 * The body of the command interpreter
246 */
247 static int
248-iocshBody (const char *pathname, const char *commandLine)
249+iocshBody (const char *pathname, const char *commandLine, int verbose)
250 {
251 FILE *fp = NULL;
252 const char *filename = NULL;
253@@ -493,7 +493,8 @@
254 else {
255 fp = fopen (pathname, "r");
256 if (fp == NULL) {
257- fprintf (stderr, "Can't open %s: %s\n", pathname, strerror (errno));
258+ if (verbose)
259+ fprintf (stderr, "Can't open %s: %s\n", pathname, strerror (errno));
260 return -1;
261 }
262 if ((filename = strrchr (pathname, '/')) == NULL)
263@@ -549,7 +550,7 @@
264 * them if they came from a script.
265 */
266 if (*raw == '#') {
267- if ((prompt == NULL) && (commandLine == NULL))
268+ if ((prompt == NULL) && (commandLine == NULL) && verbose)
269 puts(raw);
270 continue;
271 }
272@@ -564,7 +565,7 @@
273 /*
274 * Echo commands read from scripts
275 */
276- if ((prompt == NULL) && *line && (commandLine == NULL))
277+ if ((prompt == NULL) && *line && (commandLine == NULL) && verbose)
278 puts(line);
279
280 /*
281@@ -704,7 +705,7 @@
282 if (openRedirect(filename, lineno, redirects) < 0)
283 continue;
284 startRedirect(filename, lineno, redirects);
285- iocshBody(commandFile, NULL);
286+ iocshBody(commandFile, NULL, verbose);
287 stopRedirect(filename, lineno, redirects);
288 continue;
289 }
290@@ -798,7 +799,13 @@
291 int epicsShareAPI
292 iocsh (const char *pathname)
293 {
294- return iocshBody(pathname, NULL);
295+ return iocshBody(pathname, NULL, 1);
296+}
297+
298+int epicsShareAPI
299+iocsh2 (const char *pathname, int verbose)
300+{
301+ return iocshBody(pathname, NULL, verbose);
302 }
303
304 int epicsShareAPI
305@@ -806,7 +813,7 @@
306 {
307 if (cmd == NULL)
308 return 0;
309- return iocshBody(NULL, cmd);
310+ return iocshBody(NULL, cmd, 1);
311 }
312
313 /*
314
315=== modified file 'src/libCom/iocsh/iocsh.h'
316--- src/libCom/iocsh/iocsh.h 2007-03-13 17:54:23 +0000
317+++ src/libCom/iocsh/iocsh.h 2010-04-26 19:21:32 +0000
318@@ -69,6 +69,7 @@
319 epicsShareFunc void epicsShareAPI iocshFree(void);
320
321 epicsShareFunc int epicsShareAPI iocsh(const char *pathname);
322+epicsShareFunc int epicsShareAPI iocsh2(const char *pathname, int verbose);
323 epicsShareFunc int epicsShareAPI iocshCmd(const char *cmd);
324
325 /* 'weak' link to pdbbase */
326
327=== modified file 'src/libCom/iocsh/libComRegister.c'
328--- src/libCom/iocsh/libComRegister.c 2009-02-24 20:10:57 +0000
329+++ src/libCom/iocsh/libComRegister.c 2010-04-26 19:21:32 +0000
330@@ -96,6 +96,25 @@
331 epicsEnvSet (name, value);
332 }
333
334+/* epicsEnvSetIfUnset */
335+/* reuse definition of epicsEnvSet */
336+static const iocshFuncDef epicsEnvSetIfUnsetFuncDef = {"epicsEnvSetIfUnset",2,epicsEnvSetArgs};
337+static void epicsEnvSetIfUnsetCallFunc(const iocshArgBuf *args)
338+{
339+ char *name = args[0].sval;
340+ char *value = args[1].sval;
341+
342+ if (name == NULL) {
343+ printf ("Missing environment variable name argument.\n");
344+ return;
345+ }
346+ if (value == NULL) {
347+ printf ("Missing environment variable value argument.\n");
348+ return;
349+ }
350+ epicsEnvSetIfUnset (name, value);
351+}
352+
353 /* epicsParamShow */
354 static const iocshFuncDef epicsParamShowFuncDef = {"epicsParamShow",0,NULL};
355 static void epicsParamShowCallFunc(const iocshArgBuf *args)
356@@ -343,6 +362,7 @@
357 iocshRegister(&pwdFuncDef, pwdCallFunc);
358
359 iocshRegister(&epicsEnvSetFuncDef, epicsEnvSetCallFunc);
360+ iocshRegister(&epicsEnvSetIfUnsetFuncDef, epicsEnvSetIfUnsetCallFunc);
361 iocshRegister(&epicsParamShowFuncDef, epicsParamShowCallFunc);
362 iocshRegister(&epicsPrtEnvParamsFuncDef, epicsPrtEnvParamsCallFunc);
363 iocshRegister(&epicsEnvShowFuncDef, epicsEnvShowCallFunc);
364
365=== modified file 'src/libCom/macLib/macCore.c'
366--- src/libCom/macLib/macCore.c 2008-03-31 19:30:17 +0000
367+++ src/libCom/macLib/macCore.c 2010-04-26 19:21:32 +0000
368@@ -84,13 +84,6 @@
369 */
370 #define MAC_MAGIC 0xbadcafe /* ...sells sub-standard coffee? */
371
372-/*
373- * Flag bits
374- */
375-#define FLAG_SUPPRESS_WARNINGS 0x1
376-#define FLAG_USE_ENVIRONMENT 0x80
377-
378-
379 /*** Library routines ***/
380
381 /*
382@@ -130,7 +123,7 @@
383
384 /* use environment variables if so specified */
385 if (pairs && pairs[0] && !strcmp(pairs[0],"") && pairs[1] && !strcmp(pairs[1],"environ") && !pairs[3]) {
386- handle->flags |= FLAG_USE_ENVIRONMENT;
387+ handle->flags |= MAC_FLAG_USE_ENVIRONMENT;
388 }
389 else {
390 /* if supplied, load macro definitions */
391@@ -159,8 +152,8 @@
392 )
393 {
394 if ( handle && handle->magic == MAC_MAGIC ) {
395- handle->flags = (handle->flags & ~FLAG_SUPPRESS_WARNINGS) |
396- (suppress ? FLAG_SUPPRESS_WARNINGS : 0);
397+ handle->flags = (handle->flags & ~MAC_FLAG_SUPPRESS_WARNINGS) |
398+ (suppress ? MAC_FLAG_SUPPRESS_WARNINGS : 0);
399 }
400 }
401
402@@ -577,7 +570,7 @@
403 break;
404 }
405 if ( (special == FALSE) && (entry == NULL) &&
406- (handle->flags & FLAG_USE_ENVIRONMENT) ) {
407+ (handle->flags & MAC_FLAG_USE_ENVIRONMENT) ) {
408 char *value = getenv(name);
409 if (value) {
410 entry = create( handle, name, FALSE );
411@@ -794,7 +787,7 @@
412 if ( *r == '=' ) {
413 MAC_ENTRY dflt;
414 int flags = handle->flags;
415- handle->flags |= FLAG_SUPPRESS_WARNINGS;
416+ handle->flags |= MAC_FLAG_SUPPRESS_WARNINGS;
417
418 /* store its location in case we need it */
419 defval = ++r;
420@@ -812,7 +805,7 @@
421 if ( *r == ',' ) {
422 MAC_ENTRY subs;
423 int flags = handle->flags;
424- handle->flags |= FLAG_SUPPRESS_WARNINGS;
425+ handle->flags |= MAC_FLAG_SUPPRESS_WARNINGS;
426
427 subs.type = "scoped macro";
428 subs.error = FALSE;
429@@ -872,7 +865,7 @@
430 /* reference is recursive */
431 entry->error = TRUE;
432 errval = ",recursive)";
433- if ( (handle->flags & FLAG_SUPPRESS_WARNINGS) == 0 ) {
434+ if ( (handle->flags & MAC_FLAG_SUPPRESS_WARNINGS) == 0 ) {
435 errlogPrintf( "macLib: %s %s is recursive (expanding %s %s)\n",
436 entry->type, entry->name,
437 refentry->type, refentry->name );
438@@ -886,7 +879,7 @@
439 }
440 entry->error = TRUE;
441 errval = ",undefined)";
442- if ( (handle->flags & FLAG_SUPPRESS_WARNINGS) == 0 ) {
443+ if ( (handle->flags & MAC_FLAG_SUPPRESS_WARNINGS) == 0 ) {
444 errlogPrintf( "macLib: macro %s is undefined (expanding %s %s)\n",
445 refname, entry->type, entry->name );
446 }
447
448=== modified file 'src/libCom/macLib/macLib.h'
449--- src/libCom/macLib/macLib.h 2008-03-31 19:30:17 +0000
450+++ src/libCom/macLib/macLib.h 2010-04-26 19:21:32 +0000
451@@ -45,6 +45,12 @@
452 } MAC_HANDLE;
453
454 /*
455+ * Flag bits
456+ */
457+#define MAC_FLAG_SUPPRESS_WARNINGS 0x1
458+#define MAC_FLAG_USE_ENVIRONMENT 0x80
459+
460+/*
461 * Function prototypes (core library)
462 */
463 epicsShareFunc long /* 0 = OK; <0 = ERROR */
464
465=== modified file 'src/libCom/osi/os/Darwin/osdEnv.c'
466--- src/libCom/osi/os/Darwin/osdEnv.c 2009-02-23 18:11:40 +0000
467+++ src/libCom/osi/os/Darwin/osdEnv.c 2010-04-26 19:21:32 +0000
468@@ -62,6 +62,13 @@
469 }
470 }
471
472+epicsShareFunc void epicsShareAPI epicsEnvSetIfUnset (const char *name, const char *value)
473+{
474+ if (getenv(name))
475+ return;
476+ epicsEnvSet (name, value);
477+}
478+
479 /*
480 * Show the value of the specified, or all, environment variables
481 */
482
483=== modified file 'src/libCom/osi/os/default/osdEnv.c'
484--- src/libCom/osi/os/default/osdEnv.c 2004-08-27 16:04:26 +0000
485+++ src/libCom/osi/os/default/osdEnv.c 2010-04-26 19:21:32 +0000
486@@ -55,6 +55,13 @@
487 }
488 }
489
490+epicsShareFunc void epicsShareAPI epicsEnvSetIfUnset (const char *name, const char *value)
491+{
492+ if (getenv(name))
493+ return;
494+ epicsEnvSet (name, value);
495+}
496+
497 /*
498 * Show the value of the specified, or all, environment variables
499 */
500
501=== modified file 'src/libCom/osi/os/vxWorks/osdEnv.c'
502--- src/libCom/osi/os/vxWorks/osdEnv.c 2004-08-27 16:04:26 +0000
503+++ src/libCom/osi/os/vxWorks/osdEnv.c 2010-04-26 19:21:32 +0000
504@@ -54,6 +54,13 @@
505 }
506 }
507
508+epicsShareFunc void epicsShareAPI epicsEnvSetIfUnset (const char *name, const char *value)
509+{
510+ if (getenv(name))
511+ return;
512+ epicsEnvSet (name, value);
513+}
514+
515 /*
516 * Show the value of the specified, or all, environment variables
517 */

Subscribers

People subscribed via source and target branches