Merged iocshCmd-with-macros branch
This commit is contained in:
+121
-13
@@ -56,7 +56,8 @@ static struct iocshVariable *iocshVariableHead;
|
||||
static char iocshVarID[] = "iocshVar";
|
||||
extern "C" { static void varCallFunc(const iocshArgBuf *); }
|
||||
static epicsMutexId iocshTableMutex;
|
||||
static epicsThreadOnceId iocshTableOnceId = EPICS_THREAD_ONCE_INIT;
|
||||
static epicsThreadOnceId iocshOnceId = EPICS_THREAD_ONCE_INIT;
|
||||
static epicsThreadPrivateId iocshMacroHandleId;
|
||||
|
||||
/*
|
||||
* I/O redirection
|
||||
@@ -71,11 +72,17 @@ struct iocshRedirect {
|
||||
};
|
||||
|
||||
/*
|
||||
* Set up command table mutex
|
||||
* Set up module variables
|
||||
*/
|
||||
static void iocshTableOnce (void *)
|
||||
static void iocshOnce (void *)
|
||||
{
|
||||
iocshTableMutex = epicsMutexMustCreate ();
|
||||
iocshMacroHandleId = epicsThreadPrivateCreate();
|
||||
}
|
||||
|
||||
static void iocshInit (void)
|
||||
{
|
||||
epicsThreadOnce (&iocshOnceId, iocshOnce, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -84,7 +91,7 @@ static void iocshTableOnce (void *)
|
||||
static void
|
||||
iocshTableLock (void)
|
||||
{
|
||||
epicsThreadOnce (&iocshTableOnceId, iocshTableOnce, NULL);
|
||||
iocshInit();
|
||||
epicsMutexMustLock (iocshTableMutex);
|
||||
}
|
||||
|
||||
@@ -94,7 +101,6 @@ iocshTableLock (void)
|
||||
static void
|
||||
iocshTableUnlock (void)
|
||||
{
|
||||
epicsThreadOnce (&iocshTableOnceId, iocshTableOnce, NULL);
|
||||
epicsMutexUnlock (iocshTableMutex);
|
||||
}
|
||||
|
||||
@@ -475,7 +481,7 @@ static void helpCallFunc(const iocshArgBuf *args)
|
||||
* The body of the command interpreter
|
||||
*/
|
||||
static int
|
||||
iocshBody (const char *pathname, const char *commandLine)
|
||||
iocshBody (const char *pathname, const char *commandLine, const char *macros)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
const char *filename = NULL;
|
||||
@@ -498,7 +504,12 @@ iocshBody (const char *pathname, const char *commandLine)
|
||||
struct iocshCommand *found;
|
||||
void *readlineContext = NULL;
|
||||
int wasOkToBlock;
|
||||
static const char * pairs[] = {"", "environ", NULL, NULL};
|
||||
MAC_HANDLE *handle;
|
||||
char ** defines = NULL;
|
||||
|
||||
iocshInit();
|
||||
|
||||
/*
|
||||
* See if command interpreter is interactive
|
||||
*/
|
||||
@@ -540,7 +551,35 @@ iocshBody (const char *pathname, const char *commandLine)
|
||||
fprintf(epicsGetStderr(), "Out of memory!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse macro definitions, this check occurs before creating the
|
||||
* macro handle to simplify cleanup.
|
||||
*/
|
||||
|
||||
if (macros) {
|
||||
if (macParseDefns(NULL, macros, &defines) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for existing macro context or construct a new one.
|
||||
*/
|
||||
handle = (MAC_HANDLE *) epicsThreadPrivateGet(iocshMacroHandleId);
|
||||
|
||||
if (handle == NULL) {
|
||||
if (macCreateHandle(&handle, pairs)) {
|
||||
errlogMessage("iocsh: macCreateHandle failed.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
epicsThreadPrivateSet(iocshMacroHandleId, (void *) handle);
|
||||
}
|
||||
|
||||
macPushScope(handle);
|
||||
macInstallMacros(handle, defines);
|
||||
|
||||
/*
|
||||
* Read commands till EOF or exit
|
||||
*/
|
||||
@@ -585,7 +624,7 @@ iocshBody (const char *pathname, const char *commandLine)
|
||||
* Expand macros
|
||||
*/
|
||||
free(line);
|
||||
if ((line = macEnvExpand(raw)) == NULL)
|
||||
if ((line = macDefExpand(raw, handle)) == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
@@ -744,7 +783,7 @@ iocshBody (const char *pathname, const char *commandLine)
|
||||
if (openRedirect(filename, lineno, redirects) < 0)
|
||||
continue;
|
||||
startRedirect(filename, lineno, redirects);
|
||||
iocshBody(commandFile, NULL);
|
||||
iocshBody(commandFile, NULL, macros);
|
||||
stopRedirect(filename, lineno, redirects);
|
||||
continue;
|
||||
}
|
||||
@@ -811,6 +850,12 @@ iocshBody (const char *pathname, const char *commandLine)
|
||||
}
|
||||
stopRedirect(filename, lineno, redirects);
|
||||
}
|
||||
macPopScope(handle);
|
||||
|
||||
if (handle->level == 0) {
|
||||
macDeleteHandle(handle);
|
||||
epicsThreadPrivateSet(iocshMacroHandleId, NULL);
|
||||
}
|
||||
if (fp && (fp != stdin))
|
||||
fclose (fp);
|
||||
if (redirects != NULL) {
|
||||
@@ -833,17 +878,58 @@ iocshBody (const char *pathname, const char *commandLine)
|
||||
int epicsShareAPI
|
||||
iocsh (const char *pathname)
|
||||
{
|
||||
if (pathname)
|
||||
epicsEnvSet("IOCSH_STARTUP_SCRIPT", pathname);
|
||||
return iocshBody(pathname, NULL);
|
||||
return iocshLoad(pathname, NULL);
|
||||
}
|
||||
|
||||
int epicsShareAPI
|
||||
iocshCmd (const char *cmd)
|
||||
{
|
||||
return iocshRun(cmd, NULL);
|
||||
}
|
||||
|
||||
int epicsShareAPI
|
||||
iocshLoad(const char *pathname, const char *macros)
|
||||
{
|
||||
if (pathname)
|
||||
epicsEnvSet("IOCSH_STARTUP_SCRIPT", pathname);
|
||||
return iocshBody(pathname, NULL, macros);
|
||||
}
|
||||
|
||||
int epicsShareAPI
|
||||
iocshRun(const char *cmd, const char *macros)
|
||||
{
|
||||
if (cmd == NULL)
|
||||
return 0;
|
||||
return iocshBody(NULL, cmd);
|
||||
return iocshBody(NULL, cmd, macros);
|
||||
}
|
||||
|
||||
/*
|
||||
* Needed to work around the necessary limitations of macLib and
|
||||
* environment variables. In every other case of macro expansion
|
||||
* it is the expected outcome that defined macros override any
|
||||
* environment variables.
|
||||
*
|
||||
* iocshLoad/Run turn this on its head as it is very likely that
|
||||
* an epicsEnvSet command may be run within the context of their
|
||||
* calls. Thus, it would be expected that the new value would be
|
||||
* returned in any future macro expansion.
|
||||
*
|
||||
* To do so, the epicsEnvSet command needs to be able to access
|
||||
* and update the shared MAC_HANDLE that the iocsh uses. Which is
|
||||
* what this function is provided for.
|
||||
*/
|
||||
void epicsShareAPI
|
||||
iocshEnvClear(const char *name)
|
||||
{
|
||||
MAC_HANDLE *handle;
|
||||
|
||||
if (iocshMacroHandleId) {
|
||||
handle = (MAC_HANDLE *) epicsThreadPrivateGet(iocshMacroHandleId);
|
||||
|
||||
if (handle != NULL) {
|
||||
macPutValue(handle, name, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -926,6 +1012,26 @@ static void iocshCmdCallFunc(const iocshArgBuf *args)
|
||||
iocshCmd(args[0].sval);
|
||||
}
|
||||
|
||||
/* iocshLoad */
|
||||
static const iocshArg iocshLoadArg0 = { "pathname",iocshArgString};
|
||||
static const iocshArg iocshLoadArg1 = { "macros", iocshArgString};
|
||||
static const iocshArg *iocshLoadArgs[2] = {&iocshLoadArg0, &iocshLoadArg1};
|
||||
static const iocshFuncDef iocshLoadFuncDef = {"iocshLoad",2,iocshLoadArgs};
|
||||
static void iocshLoadCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
iocshLoad(args[0].sval, args[1].sval);
|
||||
}
|
||||
|
||||
/* iocshRun */
|
||||
static const iocshArg iocshRunArg0 = { "command",iocshArgString};
|
||||
static const iocshArg iocshRunArg1 = { "macros", iocshArgString};
|
||||
static const iocshArg *iocshRunArgs[2] = {&iocshRunArg0, &iocshRunArg1};
|
||||
static const iocshFuncDef iocshRunFuncDef = {"iocshRun",2,iocshRunArgs};
|
||||
static void iocshRunCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
iocshRun(args[0].sval, args[1].sval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dummy internal commands -- register and install in command table
|
||||
* so they show up in the help display
|
||||
@@ -953,6 +1059,8 @@ static void localRegister (void)
|
||||
iocshRegister(&exitFuncDef,exitCallFunc);
|
||||
iocshRegister(&helpFuncDef,helpCallFunc);
|
||||
iocshRegister(&iocshCmdFuncDef,iocshCmdCallFunc);
|
||||
iocshRegister(&iocshLoadFuncDef,iocshLoadCallFunc);
|
||||
iocshRegister(&iocshRunFuncDef,iocshRunCallFunc);
|
||||
}
|
||||
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -70,6 +70,11 @@ epicsShareFunc void epicsShareAPI iocshFree(void);
|
||||
|
||||
epicsShareFunc int epicsShareAPI iocsh(const char *pathname);
|
||||
epicsShareFunc int epicsShareAPI iocshCmd(const char *cmd);
|
||||
epicsShareFunc int epicsShareAPI iocshLoad(const char *pathname, const char* macros);
|
||||
epicsShareFunc int epicsShareAPI iocshRun(const char *cmd, const char* macros);
|
||||
|
||||
/* Makes macros that shadow environment variables work correctly with epicsEnvSet */
|
||||
epicsShareFunc void epicsShareAPI iocshEnvClear(const char *name);
|
||||
|
||||
/* 'weak' link to pdbbase */
|
||||
epicsShareExtern struct dbBase **iocshPpdbbase;
|
||||
|
||||
@@ -103,7 +103,7 @@ epicsShareAPI macCreateHandle(
|
||||
MAC_HANDLE **pHandle, /* address of variable to receive pointer */
|
||||
/* to new macro substitution context */
|
||||
|
||||
char *pairs[] ) /* pointer to NULL-terminated array of */
|
||||
const char * pairs[] ) /* pointer to NULL-terminated array of */
|
||||
/* {name,value} pair strings; a NULL */
|
||||
/* value implies undefined; a NULL */
|
||||
/* argument implies no macros */
|
||||
@@ -253,9 +253,18 @@ epicsShareAPI macPutValue(
|
||||
/* handle NULL value case: if name was found, delete entry (may be
|
||||
several entries at different scoping levels) */
|
||||
if ( value == NULL ) {
|
||||
/* FIXME: shouldn't be able to delete entries from lower scopes */
|
||||
while ( ( entry = lookup( handle, name, FALSE ) ) != NULL )
|
||||
/*
|
||||
* FIXME: shouldn't be able to delete entries from lower scopes
|
||||
* NOTE: when this is changed, this functionality of removing
|
||||
* a macro from all scopes will still be needed by iocshEnvClear
|
||||
*/
|
||||
while ( ( entry = lookup( handle, name, FALSE ) ) != NULL ) {
|
||||
delete( handle, entry );
|
||||
|
||||
if (strcmp(entry->type, "environment variable") == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,16 +20,26 @@
|
||||
|
||||
char * epicsShareAPI
|
||||
macEnvExpand(const char *str)
|
||||
{
|
||||
return macDefExpand(str, NULL);
|
||||
}
|
||||
|
||||
char * epicsShareAPI
|
||||
macDefExpand(const char *str, MAC_HANDLE *macros)
|
||||
{
|
||||
MAC_HANDLE *handle;
|
||||
static char *pairs[] = { "", "environ", NULL, NULL };
|
||||
static const char * pairs[] = { "", "environ", NULL, NULL };
|
||||
long destCapacity = 128;
|
||||
char *dest = NULL;
|
||||
int n;
|
||||
|
||||
if (macCreateHandle(&handle, pairs)){
|
||||
errlogMessage("macEnvExpand: macCreateHandle failed.");
|
||||
return NULL;
|
||||
|
||||
if (macros) {
|
||||
handle = macros;
|
||||
} else {
|
||||
if (macCreateHandle(&handle, pairs)){
|
||||
errlogMessage("macDefExpand: macCreateHandle failed.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -57,7 +67,10 @@ macEnvExpand(const char *str)
|
||||
}
|
||||
|
||||
done:
|
||||
if (macDeleteHandle(handle))
|
||||
errlogMessage("macEnvExpand: macDeleteHandle failed.");
|
||||
if (macros == NULL) {
|
||||
if (macDeleteHandle(handle)) {
|
||||
errlogMessage("macDefExpand: macDeleteHandle failed.");
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ epicsShareAPI macCreateHandle(
|
||||
MAC_HANDLE **handle, /* address of variable to receive pointer */
|
||||
/* to new macro substitution context */
|
||||
|
||||
char *pairs[] /* pointer to NULL-terminated array of */
|
||||
const char * pairs[] /* pointer to NULL-terminated array of */
|
||||
/* {name,value} pair strings; a NULL */
|
||||
/* value implies undefined; a NULL */
|
||||
/* argument implies no macros */
|
||||
@@ -151,6 +151,13 @@ epicsShareAPI macEnvExpand(
|
||||
const char *str /* string to be expanded */
|
||||
);
|
||||
|
||||
epicsShareFunc char * /* expanded string; NULL if any undefined macros */
|
||||
epicsShareAPI macDefExpand(
|
||||
const char *str, /* string to be expanded */
|
||||
MAC_HANDLE *macros /* opaque handle; can be NULL if default */
|
||||
/* special characters are to be used */
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -164,7 +164,14 @@ d) char *macEnvExpand( char *src );
|
||||
pointer to this null-terminated string. It returns NULL if the source
|
||||
string contains any undefined references.
|
||||
|
||||
e) long macReportMacros( MAC_HANDLE *handle );
|
||||
e) char *macDefExpand( char *src, MAC_HANDLE *macros );
|
||||
|
||||
This operates in the same manner as macEnvExpand, but takes an
|
||||
optional macro handle that can contain a set of macro definitions.
|
||||
These macros are appended to the set of macros from environment
|
||||
variables when expanding the string.
|
||||
|
||||
f) long macReportMacros( MAC_HANDLE *handle );
|
||||
|
||||
This reports details of current definitions to standard output, and is
|
||||
intended purely for debugging purposes.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Saskatchewan
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* osdEnv.c */
|
||||
@@ -30,13 +29,15 @@
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsStdio.h"
|
||||
#include <envDefs.h>
|
||||
#include "envDefs.h"
|
||||
#include "iocsh.h"
|
||||
|
||||
/*
|
||||
* Set the value of an environment variable
|
||||
*/
|
||||
epicsShareFunc void epicsShareAPI epicsEnvSet (const char *name, const char *value)
|
||||
{
|
||||
iocshEnvClear(name);
|
||||
setenv(name, value, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Saskatchewan
|
||||
* EPICS BASE Versions 3.13.7
|
||||
* and higher are distributed subject to a Software License Agreement found
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/* osdEnv.c */
|
||||
@@ -23,11 +22,12 @@
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "epicsStdio.h"
|
||||
#include <errlog.h>
|
||||
#include <cantProceed.h>
|
||||
#include <envDefs.h>
|
||||
#include <osiUnistd.h>
|
||||
#include "errlog.h"
|
||||
#include "cantProceed.h"
|
||||
#include "envDefs.h"
|
||||
#include "osiUnistd.h"
|
||||
#include "epicsFindSymbol.h"
|
||||
#include "iocsh.h"
|
||||
|
||||
/*
|
||||
* Set the value of an environment variable
|
||||
@@ -38,6 +38,8 @@ epicsShareFunc void epicsShareAPI epicsEnvSet (const char *name, const char *val
|
||||
{
|
||||
char *cp;
|
||||
|
||||
iocshEnvClear(name);
|
||||
|
||||
cp = mallocMustSucceed (strlen (name) + strlen (value) + 2, "epicsEnvSet");
|
||||
strcpy (cp, name);
|
||||
strcat (cp, "=");
|
||||
|
||||
@@ -28,32 +28,15 @@
|
||||
#include <envDefs.h>
|
||||
#include <osiUnistd.h>
|
||||
#include "epicsFindSymbol.h"
|
||||
|
||||
#include <iocsh.h>
|
||||
|
||||
/*
|
||||
* Set the value of an environment variable
|
||||
* Leaks memory, but the assumption is that this routine won't be
|
||||
* called often enough for the leak to be a problem.
|
||||
*/
|
||||
epicsShareFunc void epicsShareAPI epicsEnvSet (const char *name, const char *value)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
cp = mallocMustSucceed (strlen (name) + strlen (value) + 2, "epicsEnvSet");
|
||||
strcpy (cp, name);
|
||||
strcat (cp, "=");
|
||||
strcat (cp, value);
|
||||
if (putenv (cp) < 0) {
|
||||
errPrintf(
|
||||
-1L,
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"Failed to set environment parameter \"%s\" to \"%s\": %s\n",
|
||||
name,
|
||||
value,
|
||||
strerror (errno));
|
||||
free (cp);
|
||||
}
|
||||
iocshEnvClear(name);
|
||||
setenv(name, value, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -23,12 +23,12 @@
|
||||
#include <ctype.h>
|
||||
#include <envLib.h>
|
||||
|
||||
#include "epicsStdio.h"
|
||||
#include <errlog.h>
|
||||
#include <cantProceed.h>
|
||||
|
||||
#define epicsExportSharedSymbols
|
||||
#include "cantProceed.h"
|
||||
#include "epicsFindSymbol.h"
|
||||
#include "epicsStdio.h"
|
||||
#include "errlog.h"
|
||||
#include "iocsh.h"
|
||||
|
||||
/*
|
||||
* Set the value of an environment variable
|
||||
@@ -39,21 +39,18 @@ epicsShareFunc void epicsShareAPI epicsEnvSet (const char *name, const char *val
|
||||
{
|
||||
char *cp;
|
||||
|
||||
cp = mallocMustSucceed (strlen (name) + strlen (value) + 2, "epicsEnvSet");
|
||||
strcpy (cp, name);
|
||||
strcat (cp, "=");
|
||||
strcat (cp, value);
|
||||
if (putenv (cp) < 0) {
|
||||
errPrintf(
|
||||
-1L,
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
"Failed to set environment parameter \"%s\" to \"%s\": %s\n",
|
||||
name,
|
||||
value,
|
||||
strerror (errno));
|
||||
iocshEnvClear(name);
|
||||
|
||||
cp = mallocMustSucceed (strlen (name) + strlen (value) + 2, "epicsEnvSet");
|
||||
strcpy (cp, name);
|
||||
strcat (cp, "=");
|
||||
strcat (cp, value);
|
||||
if (putenv (cp) < 0) {
|
||||
errPrintf(-1L, __FILE__, __LINE__,
|
||||
"Failed to set environment parameter \"%s\" to \"%s\": %s\n",
|
||||
name, value, strerror (errno));
|
||||
free (cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -163,10 +163,10 @@ epicsExceptionTest_SRCS += epicsExceptionTest.cpp
|
||||
testHarness_SRCS += epicsExceptionTest.cpp
|
||||
TESTS += epicsExceptionTest
|
||||
|
||||
TESTPROD_HOST += macEnvExpandTest
|
||||
macEnvExpandTest_SRCS += macEnvExpandTest.c
|
||||
testHarness_SRCS += macEnvExpandTest.c
|
||||
TESTS += macEnvExpandTest
|
||||
TESTPROD_HOST += macDefExpandTest
|
||||
macDefExpandTest_SRCS += macDefExpandTest.c
|
||||
testHarness_SRCS += macDefExpandTest.c
|
||||
TESTS += macDefExpandTest
|
||||
|
||||
TESTPROD_HOST += macLibTest
|
||||
macLibTest_SRCS += macLibTest.c
|
||||
|
||||
@@ -44,7 +44,7 @@ int epicsThreadTest(void);
|
||||
int epicsTimerTest(void);
|
||||
int epicsTimeTest(void);
|
||||
int epicsTypesTest(void);
|
||||
int macEnvExpandTest(void);
|
||||
int macDefExpandTest(void);
|
||||
int macLibTest(void);
|
||||
int ringBytesTest(void);
|
||||
int ringPointerTest(void);
|
||||
@@ -92,7 +92,7 @@ void epicsRunLibComTests(void)
|
||||
runTest(epicsThreadPrivateTest);
|
||||
runTest(epicsTimeTest);
|
||||
runTest(epicsTypesTest);
|
||||
runTest(macEnvExpandTest);
|
||||
runTest(macDefExpandTest);
|
||||
runTest(macLibTest);
|
||||
runTest(ringBytesTest);
|
||||
runTest(ringPointerTest);
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2014 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* $Revision-Id$
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "macLib.h"
|
||||
#include "envDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "testMain.h"
|
||||
|
||||
|
||||
static void checkMac(MAC_HANDLE *handle, const char *name, const char *value)
|
||||
{
|
||||
char buf[20];
|
||||
|
||||
buf[19]='\0';
|
||||
if(macGetValue(handle, name, buf, 19)<0) {
|
||||
if(value)
|
||||
testFail("Macro %s undefined, expected %s", name, value);
|
||||
else
|
||||
testPass("Macro %s undefined", name);
|
||||
} else {
|
||||
if(!value)
|
||||
testFail("Macro %s is %s, expected undefined", name, buf);
|
||||
else if(strcmp(value, buf)==0)
|
||||
testPass("Macro %s is %s", name, value);
|
||||
else
|
||||
testFail("Macro %s is %s, expected %s", name, buf, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void macEnvScope(void)
|
||||
{
|
||||
MAC_HANDLE *handle;
|
||||
char **defines;
|
||||
static const char *pairs[] = { "", "environ", NULL, NULL };
|
||||
|
||||
epicsEnvSet("C","3");
|
||||
epicsEnvSet("D","4");
|
||||
epicsEnvSet("E","5");
|
||||
|
||||
macCreateHandle(&handle, pairs);
|
||||
macParseDefns(NULL, "A=1,B=2,E=15", &defines);
|
||||
macInstallMacros(handle, defines);
|
||||
|
||||
checkMac(handle, "A", "1");
|
||||
checkMac(handle, "B", "2");
|
||||
checkMac(handle, "C", "3");
|
||||
checkMac(handle, "D", "4");
|
||||
checkMac(handle, "E", "15");
|
||||
checkMac(handle, "F", NULL);
|
||||
|
||||
{
|
||||
macPushScope(handle);
|
||||
|
||||
macParseDefns(NULL, "A=11,C=13,D=14,G=7", &defines);
|
||||
macInstallMacros(handle, defines);
|
||||
|
||||
checkMac(handle, "A", "11");
|
||||
checkMac(handle, "B", "2");
|
||||
checkMac(handle, "C", "13");
|
||||
checkMac(handle, "D", "14");
|
||||
checkMac(handle, "E", "15");
|
||||
checkMac(handle, "F", NULL);
|
||||
checkMac(handle, "G", "7");
|
||||
|
||||
epicsEnvSet("D", "24");
|
||||
macPutValue(handle, "D", NULL); /* implicit when called through in iocshBody */
|
||||
epicsEnvSet("F", "6");
|
||||
macPutValue(handle, "F", NULL); /* implicit */
|
||||
epicsEnvSet("G", "17");
|
||||
macPutValue(handle, "G", NULL); /* implicit */
|
||||
|
||||
checkMac(handle, "D", "24");
|
||||
checkMac(handle, "F", "6");
|
||||
checkMac(handle, "G", "17");
|
||||
|
||||
macPopScope(handle);
|
||||
}
|
||||
|
||||
checkMac(handle, "A", "1");
|
||||
checkMac(handle, "B", "2");
|
||||
checkMac(handle, "C", "3");
|
||||
checkMac(handle, "D", "24");
|
||||
checkMac(handle, "E", "15");
|
||||
checkMac(handle, "F", "6");
|
||||
checkMac(handle, "G", "17");
|
||||
|
||||
{
|
||||
macPushScope(handle);
|
||||
|
||||
macParseDefns(NULL, "D=34,G=27", &defines);
|
||||
macInstallMacros(handle, defines);
|
||||
|
||||
checkMac(handle, "D", "34");
|
||||
checkMac(handle, "G", "27");
|
||||
|
||||
macPopScope(handle);
|
||||
}
|
||||
|
||||
checkMac(handle, "D", "24");
|
||||
|
||||
macDeleteHandle(handle);
|
||||
}
|
||||
|
||||
static void check(const char *str, const char *macros, const char *expect)
|
||||
{
|
||||
MAC_HANDLE *handle;
|
||||
char **defines;
|
||||
static const char *pairs[] = { "", "environ", NULL, NULL };
|
||||
|
||||
macCreateHandle(&handle, pairs);
|
||||
macParseDefns(NULL, macros, &defines);
|
||||
macInstallMacros(handle, defines);
|
||||
|
||||
char *got = macDefExpand(str, handle);
|
||||
int pass = -1;
|
||||
|
||||
if (expect && !got) {
|
||||
testDiag("Got NULL, expected \"%s\".\n", expect);
|
||||
pass = 0;
|
||||
}
|
||||
else if (!expect && got) {
|
||||
testDiag("Got \"%s\", expected NULL.\n", got);
|
||||
pass = 0;
|
||||
}
|
||||
else if (expect && got && strcmp(got, expect)) {
|
||||
testDiag("Got \"%s\", expected \"%s\".\n", got, expect);
|
||||
pass = 0;
|
||||
}
|
||||
testOk(pass, "%s", str);
|
||||
|
||||
macDeleteHandle(handle);
|
||||
}
|
||||
|
||||
MAIN(macDefExpandTest)
|
||||
{
|
||||
eltc(0);
|
||||
testPlan(97);
|
||||
|
||||
check("FOO", "", "FOO");
|
||||
|
||||
check("${FOO}", "", NULL);
|
||||
check("${FOO,BAR}", "", NULL);
|
||||
check("${FOO,BAR=baz}", "", NULL);
|
||||
check("${FOO,BAR=$(FOO)}", "", NULL);
|
||||
check("${FOO,FOO}", "", NULL);
|
||||
check("${FOO,FOO=$(FOO)}", "", NULL);
|
||||
check("${FOO,BAR=baz,FUM}", "", NULL);
|
||||
|
||||
check("${=}", "", "");
|
||||
check("x${=}y", "", "xy");
|
||||
|
||||
check("${,=}", "", "");
|
||||
check("x${,=}y", "", "xy");
|
||||
|
||||
check("${FOO=}", "", "");
|
||||
check("x${FOO=}y", "", "xy");
|
||||
|
||||
check("${FOO=,}", "", "");
|
||||
check("x${FOO=,}y", "", "xy");
|
||||
|
||||
check("${FOO,FOO=}", "", "");
|
||||
check("x${FOO,FOO=}y", "", "xy");
|
||||
|
||||
check("${FOO=,BAR}", "", "");
|
||||
check("x${FOO=,BAR}y", "", "xy");
|
||||
|
||||
check("${FOO=$(BAR=)}", "", "");
|
||||
check("x${FOO=$(BAR=)}y", "", "xy");
|
||||
|
||||
check("${FOO=,BAR=baz}", "", "");
|
||||
check("x${FOO=,BAR=baz}y", "", "xy");
|
||||
|
||||
check("${FOO=$(BAR),BAR=}", "", "");
|
||||
check("x${FOO=$(BAR),BAR=}y", "", "xy");
|
||||
|
||||
check("${=BAR}", "", "BAR");
|
||||
check("x${=BAR}y", "", "xBARy");
|
||||
|
||||
check("${FOO=BAR}", "", "BAR");
|
||||
check("x${FOO=BAR}y", "", "xBARy");
|
||||
|
||||
epicsEnvSet("FOO","BLETCH");
|
||||
check("${FOO}", "", "BLETCH");
|
||||
check("${FOO,FOO}", "", "BLETCH");
|
||||
check("x${FOO}y", "", "xBLETCHy");
|
||||
check("x${FOO}y${FOO}z", "", "xBLETCHyBLETCHz");
|
||||
check("${FOO=BAR}", "", "BLETCH");
|
||||
check("x${FOO=BAR}y", "", "xBLETCHy");
|
||||
check("${FOO=${BAZ}}", "", "BLETCH");
|
||||
check("${FOO=${BAZ},BAR=$(BAZ)}", "", "BLETCH");
|
||||
check("x${FOO=${BAZ}}y", "", "xBLETCHy");
|
||||
check("x${FOO=${BAZ},BAR=$(BAZ)}y", "", "xBLETCHy");
|
||||
check("${BAR=${FOO}}", "", "BLETCH");
|
||||
check("x${BAR=${FOO}}y", "", "xBLETCHy");
|
||||
check("w${BAR=x${FOO}y}z", "", "wxBLETCHyz");
|
||||
|
||||
check("${FOO,FOO=BAR}", "", "BAR");
|
||||
check("x${FOO,FOO=BAR}y", "", "xBARy");
|
||||
check("${BAR,BAR=$(FOO)}", "", "BLETCH");
|
||||
check("x${BAR,BAR=$(FOO)}y", "", "xBLETCHy");
|
||||
check("${BAR,BAR=$($(FOO)),BLETCH=GRIBBLE}", "", "GRIBBLE");
|
||||
check("x${BAR,BAR=$($(FOO)),BLETCH=GRIBBLE}y", "", "xGRIBBLEy");
|
||||
check("${$(BAR,BAR=$(FOO)),BLETCH=GRIBBLE}", "", "GRIBBLE");
|
||||
check("x${$(BAR,BAR=$(FOO)),BLETCH=GRIBBLE}y", "", "xGRIBBLEy");
|
||||
|
||||
check("${FOO}/${BAR}", "BAR=GLEEP", "BLETCH/GLEEP");
|
||||
check("x${FOO}/${BAR}y", "BAR=GLEEP", "xBLETCH/GLEEPy");
|
||||
check("${FOO,BAR}/${BAR}", "BAR=GLEEP", "BLETCH/GLEEP");
|
||||
check("${FOO,BAR=x}/${BAR}", "BAR=GLEEP", "BLETCH/GLEEP");
|
||||
check("${BAZ=BLETCH,BAR}/${BAR}", "BAR=GLEEP", "BLETCH/GLEEP");
|
||||
check("${BAZ=BLETCH,BAR=x}/${BAR}", "BAR=GLEEP", "BLETCH/GLEEP");
|
||||
|
||||
check("${${FOO}}", "BAR=GLEEP,BLETCH=BAR", "BAR");
|
||||
check("x${${FOO}}y", "BAR=GLEEP,BLETCH=BAR", "xBARy");
|
||||
check("${${FOO}=GRIBBLE}", "BAR=GLEEP,BLETCH=BAR", "BAR");
|
||||
check("x${${FOO}=GRIBBLE}y", "BAR=GLEEP,BLETCH=BAR", "xBARy");
|
||||
|
||||
check("${${FOO}}", "BAR=GLEEP,BLETCH=${BAR}", "GLEEP");
|
||||
|
||||
epicsEnvSet("FOO","${BAR}");
|
||||
check("${FOO}", "BAR=GLEEP,BLETCH=${BAR}" ,"GLEEP");
|
||||
|
||||
check("${FOO}", "BAR=${BAZ},BLETCH=${BAR}", NULL);
|
||||
|
||||
check("${FOO}", "BAR=${BAZ=GRIBBLE},BLETCH=${BAR}", "GRIBBLE");
|
||||
|
||||
check("${FOO}", "BAR=${STR1},BLETCH=${BAR},STR1=VAL1,STR2=VAL2", "VAL1");
|
||||
|
||||
check("${FOO}", "BAR=${STR2},BLETCH=${BAR},STR1=VAL1,STR2=VAL2", "VAL2");
|
||||
|
||||
check("${FOO}", "BAR=${FOO},BLETCH=${BAR},STR1=VAL1,STR2=VAL2", NULL);
|
||||
check("${FOO,FOO=$(FOO)}", "BAR=${FOO},BLETCH=${BAR},STR1=VAL1,STR2=VAL2", NULL);
|
||||
check("${FOO=$(FOO)}", "BAR=${FOO},BLETCH=${BAR},STR1=VAL1,STR2=VAL2", NULL);
|
||||
check("${FOO=$(BAR),BAR=$(FOO)}", "BAR=${FOO},BLETCH=${BAR},STR1=VAL1,STR2=VAL2", NULL);
|
||||
|
||||
macEnvScope();
|
||||
|
||||
errlogFlush();
|
||||
eltc(1);
|
||||
return testDone();
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2006 UChicago Argonne LLC, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* Operator of Los Alamos National Laboratory.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
/*
|
||||
* $Revision-Id$
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "macLib.h"
|
||||
#include "envDefs.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsUnitTest.h"
|
||||
#include "testMain.h"
|
||||
|
||||
static void check(const char *str, const char *expect)
|
||||
{
|
||||
char *got = macEnvExpand(str);
|
||||
int pass = -1;
|
||||
|
||||
if (expect && !got) {
|
||||
testDiag("Got NULL, expected \"%s\".\n", expect);
|
||||
pass = 0;
|
||||
}
|
||||
else if (!expect && got) {
|
||||
testDiag("Got \"%s\", expected NULL.\n", got);
|
||||
pass = 0;
|
||||
}
|
||||
else if (expect && got && strcmp(got, expect)) {
|
||||
testDiag("Got \"%s\", expected \"%s\".\n", got, expect);
|
||||
pass = 0;
|
||||
}
|
||||
testOk(pass, "%s", str);
|
||||
}
|
||||
|
||||
MAIN(macEnvExpandTest)
|
||||
{
|
||||
eltc(0);
|
||||
testPlan(71);
|
||||
|
||||
check("FOO", "FOO");
|
||||
|
||||
check("${FOO}", NULL);
|
||||
check("${FOO,BAR}", NULL);
|
||||
check("${FOO,BAR=baz}", NULL);
|
||||
check("${FOO,BAR=$(FOO)}", NULL);
|
||||
check("${FOO,FOO}", NULL);
|
||||
check("${FOO,FOO=$(FOO)}", NULL);
|
||||
check("${FOO,BAR=baz,FUM}", NULL);
|
||||
|
||||
check("${=}", "");
|
||||
check("x${=}y", "xy");
|
||||
|
||||
check("${,=}", "");
|
||||
check("x${,=}y", "xy");
|
||||
|
||||
check("${FOO=}", "");
|
||||
check("x${FOO=}y", "xy");
|
||||
|
||||
check("${FOO=,}", "");
|
||||
check("x${FOO=,}y", "xy");
|
||||
|
||||
check("${FOO,FOO=}", "");
|
||||
check("x${FOO,FOO=}y", "xy");
|
||||
|
||||
check("${FOO=,BAR}", "");
|
||||
check("x${FOO=,BAR}y", "xy");
|
||||
|
||||
check("${FOO=$(BAR=)}", "");
|
||||
check("x${FOO=$(BAR=)}y", "xy");
|
||||
|
||||
check("${FOO=,BAR=baz}", "");
|
||||
check("x${FOO=,BAR=baz}y", "xy");
|
||||
|
||||
check("${FOO=$(BAR),BAR=}", "");
|
||||
check("x${FOO=$(BAR),BAR=}y", "xy");
|
||||
|
||||
check("${=BAR}", "BAR");
|
||||
check("x${=BAR}y", "xBARy");
|
||||
|
||||
check("${FOO=BAR}", "BAR");
|
||||
check("x${FOO=BAR}y", "xBARy");
|
||||
|
||||
epicsEnvSet("FOO","BLETCH");
|
||||
check("${FOO}", "BLETCH");
|
||||
check("${FOO,FOO}", "BLETCH");
|
||||
check("x${FOO}y", "xBLETCHy");
|
||||
check("x${FOO}y${FOO}z", "xBLETCHyBLETCHz");
|
||||
check("${FOO=BAR}", "BLETCH");
|
||||
check("x${FOO=BAR}y", "xBLETCHy");
|
||||
check("${FOO=${BAZ}}", "BLETCH");
|
||||
check("${FOO=${BAZ},BAR=$(BAZ)}", "BLETCH");
|
||||
check("x${FOO=${BAZ}}y", "xBLETCHy");
|
||||
check("x${FOO=${BAZ},BAR=$(BAZ)}y", "xBLETCHy");
|
||||
check("${BAR=${FOO}}", "BLETCH");
|
||||
check("x${BAR=${FOO}}y", "xBLETCHy");
|
||||
check("w${BAR=x${FOO}y}z", "wxBLETCHyz");
|
||||
|
||||
check("${FOO,FOO=BAR}", "BAR");
|
||||
check("x${FOO,FOO=BAR}y", "xBARy");
|
||||
check("${BAR,BAR=$(FOO)}", "BLETCH");
|
||||
check("x${BAR,BAR=$(FOO)}y", "xBLETCHy");
|
||||
check("${BAR,BAR=$($(FOO)),BLETCH=GRIBBLE}", "GRIBBLE");
|
||||
check("x${BAR,BAR=$($(FOO)),BLETCH=GRIBBLE}y", "xGRIBBLEy");
|
||||
check("${$(BAR,BAR=$(FOO)),BLETCH=GRIBBLE}", "GRIBBLE");
|
||||
check("x${$(BAR,BAR=$(FOO)),BLETCH=GRIBBLE}y", "xGRIBBLEy");
|
||||
|
||||
epicsEnvSet("BAR","GLEEP");
|
||||
check("${FOO}/${BAR}", "BLETCH/GLEEP");
|
||||
check("x${FOO}/${BAR}y", "xBLETCH/GLEEPy");
|
||||
check("${FOO,BAR}/${BAR}", "BLETCH/GLEEP");
|
||||
check("${FOO,BAR=x}/${BAR}", "BLETCH/GLEEP");
|
||||
check("${BAZ=BLETCH,BAR}/${BAR}", "BLETCH/GLEEP");
|
||||
check("${BAZ=BLETCH,BAR=x}/${BAR}", "BLETCH/GLEEP");
|
||||
|
||||
epicsEnvSet("BLETCH","BAR");
|
||||
check("${${FOO}}", "BAR");
|
||||
check("x${${FOO}}y", "xBARy");
|
||||
check("${${FOO}=GRIBBLE}", "BAR");
|
||||
check("x${${FOO}=GRIBBLE}y", "xBARy");
|
||||
|
||||
epicsEnvSet("BLETCH","${BAR}");
|
||||
check("${${FOO}}", "GLEEP");
|
||||
|
||||
epicsEnvSet("FOO","${BAR}");
|
||||
check("${FOO}","GLEEP");
|
||||
|
||||
epicsEnvSet("BAR","${BAZ}");
|
||||
check("${FOO}", NULL);
|
||||
|
||||
epicsEnvSet("BAR","${BAZ=GRIBBLE}");
|
||||
check("${FOO}", "GRIBBLE");
|
||||
|
||||
epicsEnvSet("BAR","${STR1}");
|
||||
epicsEnvSet("STR1","VAL1");
|
||||
epicsEnvSet("STR2","VAL2");
|
||||
check("${FOO}", "VAL1");
|
||||
|
||||
epicsEnvSet("BAR","${STR2}");
|
||||
check("${FOO}", "VAL2");
|
||||
|
||||
epicsEnvSet("BAR","${FOO}");
|
||||
check("${FOO}", NULL);
|
||||
check("${FOO,FOO=$(FOO)}", NULL);
|
||||
check("${FOO=$(FOO)}", NULL);
|
||||
check("${FOO=$(BAR),BAR=$(FOO)}", NULL);
|
||||
|
||||
errlogFlush();
|
||||
eltc(1);
|
||||
return testDone();
|
||||
}
|
||||
Reference in New Issue
Block a user