Merge 7.0 into rtems5

This commit is contained in:
Andrew Johnson
2021-06-04 16:11:10 -05:00
28 changed files with 348 additions and 99 deletions

View File

@ -71,6 +71,8 @@ INSTALL_DBD = $(INSTALL_LOCATION)/dbd
INSTALL_DB = $(INSTALL_LOCATION)/db
INSTALL_CONFIG = $(INSTALL_LOCATION)/configure
FINAL_LOCATION = $(shell $(PERL) $(TOOLS)/fullPathName.pl $(INSTALL_LOCATION))
# Directory for OS independant build created files
COMMON_DIR = ../O.Common

View File

@ -155,6 +155,14 @@ CROSS_WARN=YES
# different location then uncomment and set this.
#INSTALL_LOCATION=<fullpathname>
# The location from which files placed in INSTALL_LOCATION will actually run.
# This path is compiled into executables, and so should be an absolute.
# May be used to achieve the effect of autotools. eg.
# ./configure --prefix=<FINAL_LOCATION>
# make DESTDIR=<INSTALL_LOCATION>
# Defaults to the absolute expansion of $(INSTALL_LOCATION)
#FINAL_LOCATION=
# Use POSIX thread priority scheduling (if available).
# Must be either YES or NO
USE_POSIX_THREAD_PRIORITY_SCHEDULING = YES

View File

@ -17,6 +17,61 @@ should also be read to understand what has changed since earlier releases.
<!-- Insert new items immediately below here ... -->
### epicsEnvShow accepts glob pattern
The optional argument to epicsEnvShow can now be a glob pattern.
### New function `epicsStrnGlobMatch()`
The function `epicsStrnGlobMatch(char* str, size_t len, char* pattern)`
works exactly the same as `epicsStrGlobMatch()` but takes an additional
length arguments which limits the number of characters of `str` to match.
### Automatic fallback to thread when unable to exec caRepeater
A process using libca which does not find an existing caRepeater process
will attempt to start one by running the caRepeater executable.
This is not always possible, usually when caRepeater is not in `$PATH`.
Now, instead of printing a warning, an internal caRepeater thread
will be started (as is done be RTEMS and vxWorks targets).
If this fallback occurs, the lifetime of the caRepeater thread
may be shorter than the lifetime of a separate caRepeater process
would have been.
It remains the recommended practice to explicitly start a caRepeater
instance. Examples of both systemd (`caRepeater.service`) and sysv
(`S99caRepeater`) scripts may be found under `bin/`.
### Glob pattern allowed in `var` command
When used with one argument, the `var` command can be used with a glob pattern
for printing matching variables.
### Formalize/fix `FINAL_LOCATION`
The `FINAL_LOCATION` make variable has for some time been an undocumented
means of performing a staged build. This is a build which "installs" to
a temporary location, which will later be moved to a final location.
This has now been added to `configure/CONFIG_SITE`.
Usage analogous to the autotools recipe
```sh
./configure --prefix=/usr/lib/epics
make install DESTDIR=/tmp/build
```
would be
```sh
make INSTALL_LOCATION=/tmp/build FINAL_LOCATION=/usr/lib/epics
```
`FINAL_LOCATION` is now correctly used in systemd and sysv init scripts
`caRepeater.service`, `S99caRepeater`, and `S99logServer`.
### IOCsh sets `${PWD}`
IOC shell will now ensure `${PWD}` is set on startup,

View File

@ -113,7 +113,7 @@ SCRIPTS_Linux = caRepeater.service
EXPAND += S99caRepeater@
EXPAND += caRepeater.service@
EXPAND_VARS = INSTALL_BIN=$(abspath $(INSTALL_BIN))
EXPAND_VARS = INSTALL_BIN=$(FINAL_LOCATION)/bin/$(T_A)
SRC_DIRS += $(CURDIR)/test
PROD_HOST += ca_test

View File

@ -629,8 +629,8 @@ void epicsStdCall caStartRepeaterIfNotInstalled ( unsigned repeaterPort )
* repeater's port)
*/
osiSpawnDetachedProcessReturn osptr =
osiSpawnDetachedProcess ( "CA Repeater", "caRepeater" );
if ( osptr == osiSpawnDetachedProcessNoSupport ) {
osiSpawnDetachedProcess ( "!CA Repeater", "caRepeater" );
if ( osptr != osiSpawnDetachedProcessSuccess ) {
epicsThreadId tid;
tid = epicsThreadCreate ( "CAC-repeater", epicsThreadPriorityLow,
@ -639,9 +639,6 @@ void epicsStdCall caStartRepeaterIfNotInstalled ( unsigned repeaterPort )
fprintf ( stderr, "caStartRepeaterIfNotInstalled : unable to create CA repeater daemon thread\n" );
}
}
else if ( osptr == osiSpawnDetachedProcessFail ) {
fprintf ( stderr, "caStartRepeaterIfNotInstalled (): unable to start CA repeater daemon detached process\n" );
}
}
}

View File

@ -28,7 +28,5 @@ softIoc_LIBS = $(EPICS_BASE_IOC_LIBS)
DB += softIocExit.db
FINAL_LOCATION ?= $(shell $(PERL) $(TOOLS)/fullPathName.pl $(INSTALL_LOCATION))
CLEANS += epicsInstallDir.h

View File

@ -249,7 +249,10 @@ int main(int argc, char *argv[])
} else {
if (loadedDb || ranScript) {
epicsThreadExitMain();
// non-interactive IOC. spin forever
while(true) {
epicsThreadSleep(1000.0);
}
} else {
usage(argv[0], dbd_file);

View File

@ -40,7 +40,6 @@ HTMLS += dbdToHtml.html
# Build Package Config Files
FINAL_LOCATION ?= $(shell $(PERL) $(TOOLS)/fullPathName.pl $(INSTALL_LOCATION))
C_CFLAGS += $(filter-out -g,$(filter-out -O%,$(filter-out -W%,$(CPPFLAGS))))
C_CFLAGS += $(filter-out -g,$(filter-out -O%,$(filter-out -W%,$(CFLAGS))))
PKGVARS += FINAL_LOCATION OS_CLASS CMPLR_CLASS C_CFLAGS LDFLAGS LDLIBS

View File

@ -12,9 +12,11 @@
#include <testMain.h>
#include <dbAccess.h>
#include <epicsTime.h>
#include <epicsEvent.h>
#include <epicsThread.h>
#include <errlog.h>
#include <alarm.h>
#include <callback.h>
#include "recSup.h"
#include "aiRecord.h"
@ -414,6 +416,15 @@ void testSiolWrite(const char *name,
* Asynchronous processing using simm:DELAY
*/
static void
ping(CALLBACK *pcb)
{
epicsEventId ev;
callbackGetUser(ev, pcb);
epicsEventMustTrigger(ev);
}
static
void testSimmDelay(const char *name,
epicsFloat64 *psdly,
@ -422,6 +433,14 @@ void testSimmDelay(const char *name,
epicsTimeStamp now;
const double delay = 0.01; /* 10 ms */
double diff;
epicsEventId poked;
CALLBACK cb;
memset(&cb, 0, sizeof(CALLBACK));
poked = epicsEventMustCreate(epicsEventEmpty);
callbackSetCallback(ping, &cb);
callbackSetPriority(priorityLow, &cb);
callbackSetUser(poked, &cb);
testDiag("## Asynchronous processing with simm:DELAY ##");
@ -443,14 +462,11 @@ void testSimmDelay(const char *name,
testdbPutFieldOk(namePROC, DBR_LONG, 0);
testdbGetFieldEqual(namePACT, DBR_USHORT, 1);
epicsTimeGetCurrent(&now);
epicsThreadSleep(1.75*delay);
if(testImpreciseTiming())
testTodoBegin("imprecise");
callbackRequestDelayed(&cb, 1.5 * delay);
epicsEventWait(poked);
testdbGetFieldEqual(namePACT, DBR_USHORT, 0);
diff = epicsTimeDiffInSeconds(mytime, &now);
testOk(diff >= 0.0, "time stamp is recent (%.9f sec)", diff);
if(testImpreciseTiming())
testTodoEnd();
/* Reset delay */
*psdly = -1.;

View File

@ -1126,17 +1126,26 @@ static void varHandler(const iocshVarDef *v, const char *setString)
static void varCallFunc(const iocshArgBuf *args)
{
struct iocshVariable *v;
if(args[0].sval == NULL) {
const char *name = args[0].sval;
const char *value = args[1].sval;
if (!value) {
int found = 0;
for (v = iocshVariableHead ; v != NULL ; v = v->next)
varHandler(v->pVarDef, args[1].sval);
if (!name || epicsStrGlobMatch(v->pVarDef->name, name) != 0) {
varHandler(v->pVarDef, NULL);
found = 1;
}
if (!found && name != NULL)
fprintf(epicsGetStderr(), "No var matching %s found.\n", name);
}
else {
v = (iocshVariable *)registryFind(iocshVarID, args[0].sval);
if (v == NULL) {
fprintf(epicsGetStderr(), "Var %s not found.\n", args[0].sval);
fprintf(epicsGetStderr(), "Var %s not found.\n", name);
}
else {
varHandler(v->pVarDef, args[1].sval);
varHandler(v->pVarDef, value);
}
}
}

View File

@ -24,5 +24,5 @@ iocLogServer_SYS_LIBS_WIN32 += user32 ws2_32 dbghelp
SCRIPTS_HOST = S99logServer
EXPAND += S99logServer@
EXPAND_VARS = INSTALL_BIN=$(abspath $(INSTALL_BIN))
EXPAND_VARS = INSTALL_BIN=$(FINAL_LOCATION)/bin/$(T_A)

View File

@ -23,6 +23,15 @@
#include <errno.h>
#include <ctype.h>
#ifndef vxWorks
#include <stdint.h>
#else
/* VxWorks automaticaly includes stdint.h defining SIZE_MAX in 6.9 but not earlier */
#ifndef SIZE_MAX
#define SIZE_MAX (size_t)-1
#endif
#endif
#include "epicsAssert.h"
#include "epicsStdio.h"
#include "cantProceed.h"
@ -259,30 +268,31 @@ size_t epicsStrnLen(const char *s, size_t maxlen)
return i;
}
int epicsStrGlobMatch(const char *str, const char *pattern)
int epicsStrnGlobMatch(const char *str, size_t len, const char *pattern)
{
const char *cp = NULL, *mp = NULL;
const char *mp = NULL;
size_t cp = 0, i = 0;
while ((*str) && (*pattern != '*')) {
if ((*pattern != *str) && (*pattern != '?'))
while ((i < len) && (str[i]) && (*pattern != '*')) {
if ((*pattern != str[i]) && (*pattern != '?'))
return 0;
pattern++;
str++;
i++;
}
while (*str) {
while ((i < len) && str[i]) {
if (*pattern == '*') {
if (!*++pattern)
return 1;
mp = pattern;
cp = str+1;
cp = i+1;
}
else if ((*pattern == *str) || (*pattern == '?')) {
else if ((*pattern == str[i]) || (*pattern == '?')) {
pattern++;
str++;
i++;
}
else {
pattern = mp;
str = cp++;
i = cp++;
}
}
while (*pattern == '*')
@ -290,6 +300,10 @@ int epicsStrGlobMatch(const char *str, const char *pattern)
return !*pattern;
}
int epicsStrGlobMatch(const char *str, const char *pattern) {
return epicsStrnGlobMatch(str, SIZE_MAX, pattern);
}
char * epicsStrtok_r(char *s, const char *delim, char **lasts)
{
const char *spanp;

View File

@ -36,7 +36,30 @@ LIBCOM_API char * epicsStrnDup(const char *s, size_t len);
LIBCOM_API int epicsStrPrintEscaped(FILE *fp, const char *s, size_t n);
#define epicsStrSnPrintEscaped epicsStrnEscapedFromRaw
LIBCOM_API size_t epicsStrnLen(const char *s, size_t maxlen);
/** Matches a string against a pattern.
*
* Checks if str matches the glob style pattern, which may contain ? or * wildcards.
* A ? matches any single character.
* A * matched any sub-string.
*
* @returns 1 if str matches the pattern, 0 if not.
*
* @since EPICS 3.14.7
*/
LIBCOM_API int epicsStrGlobMatch(const char *str, const char *pattern);
/** Matches a string against a pattern.
*
* Like epicsStrGlobMatch but with limited string length.
* If the length of str is less than len, the full string is matched.
*
* @returns 1 if the first len characters of str match the pattern, 0 if not.
*
* @since UNRELEASED
*/
LIBCOM_API int epicsStrnGlobMatch(const char *str, size_t len, const char *pattern);
LIBCOM_API char * epicsStrtok_r(char *s, const char *delim, char **lasts);
LIBCOM_API unsigned int epicsStrHash(const char *str, unsigned int seed);
LIBCOM_API unsigned int epicsMemHash(const char *str, size_t length,

View File

@ -59,6 +59,7 @@
#include <stddef.h>
#include "libComAPI.h"
#include "compilerDependencies.h"
#ifdef __cplusplus
extern "C" {
@ -142,8 +143,12 @@ LIBCOM_API void epicsThreadRealtimeLock(void);
* call this routine. This should be the last call in main, except the
* final return. On most systems epicsThreadExitMain never returns.This
* must only be called by the main thread.
*
* @deprecated Deprecated for lack of use. Please report any usage.
* Recommended replacement is loop + epicsThreadSleep(),
* epicsEventMustWait(), or similar.
**/
LIBCOM_API void epicsStdCall epicsThreadExitMain(void);
LIBCOM_API void epicsStdCall epicsThreadExitMain(void) EPICS_DEPRECATED;
/** For use with epicsThreadCreateOpt() */
typedef struct epicsThreadOpts {

View File

@ -219,6 +219,8 @@ threadWrapper (rtems_task_argument arg)
*/
void epicsThreadExitMain (void)
{
cantProceed("epicsThreadExitMain() has been deprecated for lack of usage."
" Please report if you see this message.");
}
static rtems_status_code

View File

@ -15,11 +15,11 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include "epicsStdio.h"
#include "epicsString.h"
#include "errlog.h"
#include "envDefs.h"
#include "osiUnistd.h"
@ -61,18 +61,10 @@ LIBCOM_API void epicsStdCall epicsEnvUnset (const char *name)
*/
LIBCOM_API void epicsStdCall epicsEnvShow (const char *name)
{
if (name == NULL) {
extern char **environ;
char **sp;
for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++)
for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++) {
if (!name || epicsStrnGlobMatch(*sp, strchr(*sp, '=') - *sp, name))
printf ("%s\n", *sp);
}
else {
const char *cp = getenv (name);
if (cp == NULL)
printf ("%s is not an environment variable.\n", name);
else
printf ("%s=%s\n", name, cp);
}
}

View File

@ -92,17 +92,27 @@ LIBCOM_API epicsEventStatus epicsEventWait ( epicsEventId pSem )
LIBCOM_API epicsEventStatus epicsEventWaitWithTimeout (
epicsEventId pSem, double timeOut )
{
static const unsigned nSec100PerSec = 10000000u;
/* waitable timers use 100 nanosecond intervals, like FILETIME */
static const unsigned ivalPerSec = 10000000u; /* number of 100ns intervals per second */
static const unsigned mSecPerSec = 1000u; /* milliseconds per second */
HANDLE handles[2];
DWORD status;
LARGE_INTEGER tmo;
HANDLE timer;
LONGLONG nIvals; /* number of intervals */
if ( timeOut <= 0.0 ) {
tmo.QuadPart = 0u;
}
else if ( timeOut >= INFINITE / mSecPerSec ) {
/* we need to apply a maximum wait time to stop an overflow. We choose (INFINITE - 1) milliseconds,
to be compatible with previous WaitForSingleObject() implementation */
nIvals = (LONGLONG)(INFINITE - 1) * (ivalPerSec / mSecPerSec);
tmo.QuadPart = -nIvals; /* negative value means a relative time offset for timer */
}
else {
tmo.QuadPart = -((LONGLONG)(timeOut * nSec100PerSec + 0.5));
nIvals = (LONGLONG)(timeOut * ivalPerSec + 0.999999);
tmo.QuadPart = -nIvals;
}
if (tmo.QuadPart < 0) {

View File

@ -50,10 +50,14 @@ LIBCOM_API osiGetUserNameReturn epicsStdCall osiGetUserName (char *pBuf, unsigne
LIBCOM_API osiSpawnDetachedProcessReturn epicsStdCall osiSpawnDetachedProcess
( const char *pProcessName, const char *pBaseExecutableName )
{
BOOL silent = pProcessName && pProcessName[0]=='!';
BOOL status;
STARTUPINFO startupInfo;
PROCESS_INFORMATION processInfo;
if(silent)
pProcessName++; /* skip '!' */
GetStartupInfo ( &startupInfo );
startupInfo.lpReserved = NULL;
startupInfo.lpTitle = (char *) pProcessName;
@ -115,7 +119,7 @@ LIBCOM_API osiSpawnDetachedProcessReturn epicsStdCall osiSpawnDetachedProcess
/* Free the buffer. */
LocalFree (errStrMsgBuf);
}
else {
else if(!silent) {
fprintf (stderr, "!!WARNING!!\n");
fprintf (stderr, "Unable to locate executable \"%s\".\n", pBaseExecutableName);
fprintf (stderr, "You may need to modify your \"path\" environment variable.\n");

View File

@ -260,7 +260,8 @@ static void epicsParmCleanupWIN32 ( win32ThreadParam * pParm )
*/
LIBCOM_API void epicsStdCall epicsThreadExitMain ( void )
{
_endthread ();
cantProceed("epicsThreadExitMain() has been deprecated for lack of usage."
" Please report if you see this message.");
}
/*
@ -818,15 +819,25 @@ HANDLE osdThreadGetTimer()
*/
LIBCOM_API void epicsStdCall epicsThreadSleep ( double seconds )
{
static const unsigned nSec100PerSec = 10000000u;
/* waitable timers use 100 nanosecond intervals, like FILETIME */
static const unsigned ivalPerSec = 10000000u; /* number of 100ns intervals per second */
static const unsigned mSecPerSec = 1000u; /* milliseconds per second */
LARGE_INTEGER tmo;
HANDLE timer;
LONGLONG nIvals; /* number of intervals */
if ( seconds <= 0.0 ) {
tmo.QuadPart = 0u;
}
else if ( seconds >= INFINITE / mSecPerSec ) {
/* we need to apply a maximum wait time to stop an overflow. We choose (INFINITE - 1) milliseconds,
to be compatible with previous WaitForSingleObject() implementation */
nIvals = (LONGLONG)(INFINITE - 1) * (ivalPerSec / mSecPerSec);
tmo.QuadPart = -nIvals; /* negative value means a relative time offset for timer */
}
else {
tmo.QuadPart = -((LONGLONG)(seconds * nSec100PerSec + 0.5));
nIvals = (LONGLONG)(seconds * ivalPerSec + 0.999999);
tmo.QuadPart = -nIvals;
}
if (tmo.QuadPart == 0) {

View File

@ -15,11 +15,11 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include "epicsStdio.h"
#include "epicsString.h"
#include "epicsVersion.h"
#include "errlog.h"
#include "envDefs.h"
@ -68,18 +68,11 @@ LIBCOM_API void epicsStdCall epicsEnvUnset (const char *name)
*/
LIBCOM_API void epicsStdCall epicsEnvShow (const char *name)
{
if (name == NULL) {
extern char **environ;
char **sp;
for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++)
for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++) {
if (!name || epicsStrnGlobMatch(*sp, strchr(*sp, '=') - *sp, name))
printf ("%s\n", *sp);
}
else {
const char *cp = getenv (name);
if (cp == NULL)
printf ("%s is not an environment variable.\n", name);
else
printf ("%s=%s\n", name, cp);
}
}

View File

@ -24,7 +24,9 @@
#include <unistd.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pwd.h>
#include <fcntl.h>
#include "osiProcess.h"
#include "errlog.h"
@ -61,12 +63,22 @@ LIBCOM_API osiSpawnDetachedProcessReturn epicsStdCall osiSpawnDetachedProcess
(const char *pProcessName, const char *pBaseExecutableName)
{
int status;
int silent = pProcessName && pProcessName[0]=='!';
int fds[2]; /* [reader, writer] */
if(silent)
pProcessName++; /* skip '!' */
if(pipe(fds))
return osiSpawnDetachedProcessFail;
/*
* create a duplicate process
*/
status = fork ();
if (status < 0) {
close(fds[0]);
close(fds[1]);
return osiSpawnDetachedProcessFail;
}
@ -75,11 +87,29 @@ LIBCOM_API osiSpawnDetachedProcessReturn epicsStdCall osiSpawnDetachedProcess
* in the initiating (parent) process
*/
if (status) {
return osiSpawnDetachedProcessSuccess;
osiSpawnDetachedProcessReturn ret = osiSpawnDetachedProcessSuccess;
char buf;
ssize_t n;
close(fds[1]);
n = read(fds[0], &buf, 1);
/* Success if child exec'd without sending a '!'.
* Of course child may crash soon after, but can't
* wait around for this to happen.
*/
if(n!=0) {
ret = osiSpawnDetachedProcessFail;
}
/*
* This is executed only by the new child process.
close(fds[0]);
return ret;
}
close(fds[0]);
(void)fcntl ( fds[1], F_SETFD, FD_CLOEXEC );
/* This is executed only by the new child process.
* Since we may be called from a library, we don't assume that
* all other code has set properly set FD_CLOEXEC.
* Close all open files except for STDIO, so they will not
* be inherited by the new program.
*/
@ -89,6 +119,8 @@ LIBCOM_API osiSpawnDetachedProcessReturn epicsStdCall osiSpawnDetachedProcess
if (fd==STDIN_FILENO) continue;
if (fd==STDOUT_FILENO) continue;
if (fd==STDERR_FILENO) continue;
/* pipe to our parent will be closed automatically via FD_CLOEXEC */
if (fd==fds[1]) continue;
close (fd);
}
}
@ -109,12 +141,16 @@ LIBCOM_API osiSpawnDetachedProcessReturn epicsStdCall osiSpawnDetachedProcess
* Run the specified executable
*/
status = execlp (pBaseExecutableName, pBaseExecutableName, (char *)NULL);
if ( status < 0 ) {
if ( status < 0 && !silent ) {
fprintf ( stderr, "**** The executable \"%s\" couldn't be located\n", pBaseExecutableName );
fprintf ( stderr, "**** because of errno = \"%s\".\n", strerror (errno) );
fprintf ( stderr, "**** You may need to modify your PATH environment variable.\n" );
fprintf ( stderr, "**** Unable to start \"%s\" process.\n", pProcessName);
}
/* signal error to parent */
ssize_t ret = write(fds[1], "!", 1);
(void)ret; /* not much we could do about this */
close(fds[1]);
/* Don't run our parent's atexit() handlers */
_exit ( -1 );
}

View File

@ -690,6 +690,10 @@ LIBCOM_API void epicsStdCall epicsThreadExitMain(void)
epicsThreadOSD *pthreadInfo;
epicsThreadInit();
cantProceed("epicsThreadExitMain() has been deprecated for lack of usage."
" Please report if you see this message.");
pthreadInfo = (epicsThreadOSD *)pthread_getspecific(getpthreadInfo);
if(pthreadInfo==NULL)
pthreadInfo = createImplicit();

View File

@ -16,17 +16,18 @@
/* This is needed for vxWorks 6.8 to prevent an obnoxious compiler warning */
#define _VSB_CONFIG_FILE <../lib/h/config/vsbConfig.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <envLib.h>
#include "epicsFindSymbol.h"
#include "epicsStdio.h"
#include "epicsString.h"
#include "errlog.h"
#include "iocsh.h"
/*
* Set the value of an environment variable
* Leaks memory, but the assumption is that this routine won't be
@ -86,14 +87,12 @@ LIBCOM_API void epicsStdCall epicsEnvUnset (const char *name)
*/
LIBCOM_API void epicsStdCall epicsEnvShow (const char *name)
{
if (name == NULL) {
envShow (0);
}
else {
const char *cp = getenv (name);
if (cp == NULL)
printf ("%s is not an environment variable.\n", name);
else
printf ("%s=%s\n", name, cp);
extern char **ppGlobalEnviron; /* Used in 'environ' macro but not declared in envLib.h */
char **sp;
for (sp = environ ; (sp != NULL) && (*sp != NULL) ; sp++) {
if (!**sp) continue; /* skip unset environment variables */
if (!name || epicsStrnGlobMatch(*sp, strchr(*sp, '=') - *sp, name))
printf ("%s\n", *sp);
}
}

View File

@ -353,7 +353,8 @@ void epicsThreadResume(epicsThreadId id)
void epicsThreadExitMain(void)
{
errlogPrintf("epicsThreadExitMain was called for vxWorks. Why?\n");
cantProceed("epicsThreadExitMain() has been deprecated for lack of usage."
" Please report if you see this message.");
}
unsigned int epicsThreadGetPriority(epicsThreadId id)

View File

@ -73,6 +73,43 @@ void testGlob(void) {
testOk1(epicsStrGlobMatch("hello","he*"));
testOk1(epicsStrGlobMatch("hello","*lo"));
testOk1(epicsStrGlobMatch("hello","*"));
/* epicsStrnGlobMatch */
testOk1(epicsStrnGlobMatch("xyzq",3,"xyz"));
testOk1(!epicsStrnGlobMatch("xyzq",3,"xyzm"));
testOk1(!epicsStrnGlobMatch("xyzm",3,"xyzm"));
testOk1(!epicsStrnGlobMatch("xyzm",0,"xyzm"));
testOk1(!epicsStrnGlobMatch("xyzq",3,""));
testOk1(epicsStrnGlobMatch("xyz",0,""));
testOk1(epicsStrnGlobMatch("xyz",0,"*"));
testOk1(!epicsStrnGlobMatch("xyz",0,"?"));
testOk1(!epicsStrnGlobMatch("xyz",0,"?*"));
testOk1(epicsStrnGlobMatch("hello!",5,"h*o"));
testOk1(!epicsStrnGlobMatch("hello!",5,"h*x"));
testOk1(!epicsStrnGlobMatch("hellxo",5,"h*o"));
testOk1(epicsStrnGlobMatch("hello!",5,"he?lo"));
testOk1(!epicsStrnGlobMatch("hello!",5,"he?xo"));
testOk1(epicsStrnGlobMatch("hello!",5,"he??o"));
testOk1(!epicsStrnGlobMatch("helllo!",5,"he?lo"));
testOk1(!epicsStrnGlobMatch("hello world!",10,"he*o w*d"));
testOk1(epicsStrnGlobMatch("hello world!",11,"he*o w*d"));
testOk1(!epicsStrnGlobMatch("hello world!",12,"he*o w*d"));
testOk1(!epicsStrnGlobMatch("hello_world!",11,"he*o w*d"));
testOk1(epicsStrnGlobMatch("hello world!",11,"he**d"));
testOk1(epicsStrnGlobMatch("hello hello world!!!!!!!!!!!!!!!!!!!!",17,"he*o w*d"));
testOk1(!epicsStrnGlobMatch("hello hello world",15,"he*o w*d"));
testOk1(epicsStrnGlobMatch("hello!!",5,"he*"));
testOk1(epicsStrnGlobMatch("hello!!",5,"*lo"));
testOk1(epicsStrnGlobMatch("hello!!",5,"*"));
}
static
@ -118,7 +155,7 @@ MAIN(epicsStringTest)
char *s;
int status;
testPlan(401);
testPlan(427);
testChars();

View File

@ -8,9 +8,19 @@ RULES = $(EPICS_BASE)
# RELEASE files point to other application tops
include $(TOP)/configure/RELEASE
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common
ifdef T_A
-include $(TOP)/configure/RELEASE.Common.$(T_A)
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
-include $(TOP)/configure/RELEASE.Common.$(T_A)
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
endif
# Check EPICS_BASE is set properly
ifneq (file,$(origin EPICS_BASE))
$(error EPICS_BASE must be set in a configure/RELEASE file)
else
ifeq ($(wildcard $(EPICS_BASE)/configure/CONFIG_BASE),)
$(error EPICS_BASE does not point to an EPICS installation)
endif
endif
CONFIG = $(RULES)/configure
@ -19,11 +29,17 @@ include $(CONFIG)/CONFIG
# Override the Base definition:
INSTALL_LOCATION = $(TOP)
# CONFIG_SITE files contain other build configuration settings
# CONFIG_SITE files contain local build configuration settings
include $(TOP)/configure/CONFIG_SITE
# Host-arch specific settings
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
ifdef T_A
# Target-arch specific settings
-include $(TOP)/configure/CONFIG_SITE.Common.$(T_A)
# Host & target specific settings
-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
endif

View File

@ -1,13 +1,11 @@
# CONFIG - Load build configuration data
#
# Do not make changes in this file, any site-specific
# overrides should be given in a CONFIG_SITE file.
# Do not make changes to this file!
# Where the build rules come from
# Allow user to override where the build rules come from
RULES = $(EPICS_BASE)
INSTALL_IDLFILE = $(INSTALL)
# RELEASE files point to other application tops
include $(TOP)/configure/RELEASE
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH)
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common
@ -17,27 +15,38 @@ ifdef T_A
-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A)
endif
# Check EPICS_BASE is set properly
ifneq (file,$(origin EPICS_BASE))
$(error EPICS_BASE must be set in a configure/RELEASE file)
else
ifeq ($(wildcard $(EPICS_BASE)/configure/CONFIG_BASE),)
$(error EPICS_BASE does not point to an EPICS installation)
endif
endif
CONFIG = $(RULES)/configure
include $(CONFIG)/CONFIG
# Override some Base definitions
# Override the Base definition:
INSTALL_LOCATION = $(TOP)
# CONFIG_SITE files contain build configuration overrides
# CONFIG_SITE files contain local build configuration settings
include $(TOP)/configure/CONFIG_SITE
# Host-arch specific settings
# Host-arch specific settings for extensions are in configure/os
-include $(TOP)/configure/os/CONFIG_SITE.$(EPICS_HOST_ARCH).Common
ifdef T_A
# Target-arch specific settings for extensions are in configure/os
-include $(TOP)/configure/os/CONFIG_SITE.Common.$(T_A)
# Host & target specific settings for extensions are in configure/os
-include $(TOP)/configure/os/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
endif
# Additional settings for extensions
INSTALL_IDLFILE = $(INSTALL)
ifdef INSTALL_LOCATION_EXTENSIONS
INSTALL_LOCATION = $(INSTALL_LOCATION_EXTENSIONS)
endif
ifdef T_A
# Target-arch specific settings
-include $(TOP)/configure/os/CONFIG_SITE.Common.$(T_A)
# Host & target specific combination settings
-include $(TOP)/configure/os/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A)
endif

View File

@ -227,6 +227,12 @@ sub envPaths {
# Check RELEASE file consistency with support modules
#
sub checkRelease {
die "\nEPICS_BASE must be set in a configure/RELEASE file.\n\n"
unless grep(m/^(EPICS_BASE)$/, @apps) &&
exists $macros{EPICS_BASE} &&
$macros{EPICS_BASE} ne '' &&
-f "$macros{EPICS_BASE}/configure/CONFIG_BASE";
my $status = 0;
delete $macros{RULES};
delete $macros{TOP};