Merged iocshCmd-with-macros branch

This commit is contained in:
Andrew Johnson
2014-10-06 23:39:23 -05:00
14 changed files with 466 additions and 237 deletions
+121 -13
View File
@@ -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" */
+5
View File
@@ -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;
+12 -3
View File
@@ -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 -7
View File
@@ -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;
}
+8 -1
View File
@@ -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
+8 -1
View File
@@ -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.
+4 -3
View File
@@ -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);
}
+8 -6
View File
@@ -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, "=");
+3 -20
View File
@@ -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);
}
/*
+15 -18
View File
@@ -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);
}
}
}
/*
+4 -4
View File
@@ -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
+2 -2
View File
@@ -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);
+256
View File
@@ -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();
}
-159
View File
@@ -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();
}