EPICS Home

Experimental Physics and Industrial Control System


 
2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  <20122013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  <20122013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: [Merge] lp:~jlmuir/epics-base/iocsh-if-flow-control-3.14 into lp:epics-base
From: "J. Lewis Muir" <[email protected]>
To: [email protected]
Date: Mon, 09 Jan 2012 18:17:26 -0000
J. Lewis Muir has proposed merging lp:~jlmuir/epics-base/iocsh-if-flow-control-3.14 into lp:epics-base.

Requested reviews:
  EPICS Core Developers (epics-core)

For more details, see:
https://code.launchpad.net/~jlmuir/epics-base/iocsh-if-flow-control-3.14/+merge/87972

(Same as before, but I forgot to update my branch before pushing, so the diff was not clean.)

Adds conditional execution (i.e. "if" flow control) to iocsh.

A case where this would be useful is when some hardware might be present or not, and one wants to easily include or exclude parts of an iocsh script.  Another case would be when one wants to easily include or exclude certain behavior.  Instead of having to comment in or out parts of an iocsh script, one can simply set a "flag" environment variable that indicates whether to include certain parts of an iocsh script.

Includes iocshTest to test the new behavior as part of the standard EPICS Base testing facility.

If accepted, I can provide appropriate changes to the Application Developer's Guide to document this.
-- 
https://code.launchpad.net/~jlmuir/epics-base/iocsh-if-flow-control-3.14/+merge/87972
Your team EPICS Core Developers is requested to review the proposed merge of lp:~jlmuir/epics-base/iocsh-if-flow-control-3.14 into lp:epics-base.
=== modified file 'configure/RULES.Db'
--- configure/RULES.Db	2011-11-14 23:42:50 +0000
+++ configure/RULES.Db	2012-01-09 18:16:27 +0000
@@ -24,8 +24,8 @@
 # dbExpand
 INSTALL_DBDFLAGS += -I $(INSTALL_DBD)
 INSTALL_DBFLAGS += -I $(INSTALL_DB)
-DBDFLAGS = $(USR_DBDFLAGS) -I . -I .. $(INSTALL_DBDFLAGS) $(RELEASE_DBDFLAGS)
-DBFLAGS = $($*_DBFLAGS) $(USR_DBFLAGS) -I. -I.. $(INSTALL_DBFLAGS) $(RELEASE_DBFLAGS)
+DBDFLAGS = $(USR_DBDFLAGS) -I. -I.. -I$(COMMON_DIR) $(INSTALL_DBDFLAGS) $(RELEASE_DBDFLAGS)
+DBFLAGS = $($*_DBFLAGS) $(USR_DBFLAGS) -I. -I.. -I$(COMMON_DIR) $(INSTALL_DBFLAGS) $(RELEASE_DBFLAGS)
 
 #####################################################
 # To allow os specific dbd files AND have the -j option work properly,

=== modified file 'configure/os/CONFIG.darwinCommon.darwinCommon'
--- configure/os/CONFIG.darwinCommon.darwinCommon	2010-10-05 19:27:37 +0000
+++ configure/os/CONFIG.darwinCommon.darwinCommon	2012-01-09 18:16:27 +0000
@@ -53,20 +53,6 @@
 OPT_CXXFLAGS_YES += -g
 
 #
-# The following two definitions enable the use of DarwinPorts packages.
-#
-OP_SYS_INCLUDES += -I/opt/local/include
-# dir/firstword/wildcard used to avoid warning -L: directory name (...) does not exist
-OP_SYS_LDFLAGS +=  $(addprefix -L,$(dir $(firstword $(wildcard /opt/local/lib/*))))
-
-#
-# The following two definitions enable the use of Fink packages.
-#
-OP_SYS_INCLUDES += -I/sw/include
-# dir/firstword/wildcard used to avoid warning -L: directory name (...) does not exist
-OP_SYS_LDFLAGS +=  $(addprefix -L,$(dir $(firstword $(wildcard /sw/lib/*))))
-
-#
 # Libraries for command-line editing.
 #
 LDLIBS_READLINE = -lreadline

=== added file 'configure/os/CONFIG_SITE.darwinCommon.darwinCommon'
--- configure/os/CONFIG_SITE.darwinCommon.darwinCommon	1970-01-01 00:00:00 +0000
+++ configure/os/CONFIG_SITE.darwinCommon.darwinCommon	2012-01-09 18:16:27 +0000
@@ -0,0 +1,20 @@
+# CONFIG_SITE.darwinCommon.darwinCommon
+#
+# $Revision-Id$
+# This file is maintained by the build community.
+#
+# Site specific definitions for darwin builds
+#-------------------------------------------------------
+
+# Uncomment the following two definitions to enable the use of DarwinPorts packages.
+#
+#OP_SYS_INCLUDES += -I/opt/local/include
+# dir/firstword/wildcard used to avoid warning -L: directory name (...) does not exist
+#OP_SYS_LDFLAGS +=  $(addprefix -L,$(dir $(firstword $(wildcard /opt/local/lib/*))))
+
+# Uncomment the following two definitions to enable the use of Fink packages.
+#
+#OP_SYS_INCLUDES += -I/sw/include
+# dir/firstword/wildcard used to avoid warning -L: directory name (...) does not exist
+#OP_SYS_LDFLAGS +=  $(addprefix -L,$(dir $(firstword $(wildcard /sw/lib/*))))
+

=== modified file 'src/ca/client/udpiiu.cpp'
--- src/ca/client/udpiiu.cpp	2011-07-26 22:23:34 +0000
+++ src/ca/client/udpiiu.cpp	2012-01-09 18:16:27 +0000
@@ -397,6 +397,11 @@
     } while ( ! this->iiu.shutdownCmd );
 }
 
+/* for sunpro compiler */
+udpiiu::M_repeaterTimerNotify::~M_repeaterTimerNotify () 
+{
+}
+
 /*
  *  udpiiu::M_repeaterTimerNotify::repeaterRegistrationMessage ()
  *

=== modified file 'src/ca/client/udpiiu.h'
--- src/ca/client/udpiiu.h	2011-09-08 23:57:14 +0000
+++ src/ca/client/udpiiu.h	2012-01-09 18:16:27 +0000
@@ -143,6 +143,7 @@
     public:
         M_repeaterTimerNotify ( udpiiu & iiu ) : 
             m_udpiiu ( iiu ) {}
+        ~M_repeaterTimerNotify (); /* for sunpro compiler */
         // repeaterTimerNotify
         void repeaterRegistrationMessage ( 
             unsigned attemptNumber );

=== modified file 'src/ca/legacy/pcas/generic/st/casStreamOS.cc'
--- src/ca/legacy/pcas/generic/st/casStreamOS.cc	2011-04-05 21:08:49 +0000
+++ src/ca/legacy/pcas/generic/st/casStreamOS.cc	2012-01-09 18:16:27 +0000
@@ -231,6 +231,18 @@
 }
 
 //
+// casStreamOS::armRecv ()
+//
+inline void casStreamOS::armRecv()
+{
+	if ( ! this->pRdReg ) {
+		if ( ! this->inBufFull() ) {
+			this->pRdReg = new casStreamReadReg ( *this );
+		}
+	}
+}
+
+//
 // casStreamIOWakeup::expire()
 //
 // This is called whenever asynchronous IO completes
@@ -298,18 +310,6 @@
 }
 
 //
-// casStreamOS::armRecv ()
-//
-inline void casStreamOS::armRecv()
-{
-	if ( ! this->pRdReg ) {
-		if ( ! this->inBufFull() ) {
-			this->pRdReg = new casStreamReadReg ( *this );
-		}
-	}
-}
-
-//
 // casStreamOS::disarmRecv ()
 //
 inline void casStreamOS::disarmRecv ()

=== modified file 'src/libCom/iocsh/iocsh.cpp'
--- src/libCom/iocsh/iocsh.cpp	2011-04-26 20:18:30 +0000
+++ src/libCom/iocsh/iocsh.cpp	2012-01-09 18:16:27 +0000
@@ -13,6 +13,7 @@
 /* Adapted to C++ by Eric Norum   Date: 18DEC2000 */
 
 #include <stddef.h>
+#include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <ctype.h>
@@ -71,6 +72,17 @@
 };
 
 /*
+ * Reserved words
+ */
+#define RESERVED_WORDS_SIZE 4
+static const char * const reservedWords[] = { "if", "elif", "else", "endif" };
+
+/*
+ * if-statement
+ */
+#define IF_STATEMENT_STACK_CAPACITY 16
+
+/*
  * Set up command table mutex
  */
 static void iocshTableOnce (void *)
@@ -107,6 +119,14 @@
     int i;
 
     iocshTableLock ();
+    for (i = 0; i < RESERVED_WORDS_SIZE; i++) {
+        if (strcmp (reservedWords[i], piocshFuncDef->name) == 0) {
+            iocshTableUnlock ();
+            errlogPrintf ("iocshRegister failed to add \"%s\" because it is a reserved word\n",
+                piocshFuncDef->name);
+            return;
+        }
+    }
     for (l = NULL, p = iocshCommandHead ; p != NULL ; l = p, p = p->next) {
         i = strcmp (piocshFuncDef->name, p->pFuncDef->name);
         if (i == 0) {
@@ -122,7 +142,7 @@
     if (!registryAdd(iocshCmdID, piocshFuncDef->name, (void *)n)) {
         free (n);
         iocshTableUnlock ();
-        errlogPrintf ("iocshRegister failed to add %s\n", piocshFuncDef->name);
+        errlogPrintf ("iocshRegister failed to add \"%s\"\n", piocshFuncDef->name);
         return;
     }
     if (l == NULL) {
@@ -388,6 +408,205 @@
 }
 
 /*
+ * Returns the index of the beginning of the next line in commandLines.
+ *
+ * @param commandLines  command lines string
+ * @param beginIndex    index in commandLines from which to start search,
+ *                      inclusive
+ *
+ * @return index of next line beginning found; a negative value if not found
+ */
+static int
+findLineBeginning(const char *commandLines, int beginIndex)
+{
+    int result;
+
+    if (beginIndex < 0) return 0;
+    for (result = beginIndex; commandLines[result] != '\0'; result++) {
+        if (commandLines[result] == '\n') break;
+        if (commandLines[result] == '\r' && commandLines[result+1] != '\n') break;
+    }
+    if (commandLines[result] == '\0') return -1;
+    result++;
+    return (commandLines[result] == '\0') ? -1 : result;
+}
+
+/*
+ * Removes a line terminator from line by overwriting it with NUL
+ * characters.
+ *
+ * @param line        line from which terminator should be removed
+ * @param lineLength  length of line (excluding NUL string terminator)
+ */
+static void
+removeLineTerminator(char *line, size_t lineLength)
+{
+    if (lineLength <= 0) return;
+    if (line[lineLength-1] == '\n') {
+        line[lineLength-1] = '\0';
+        if (lineLength - 1 == 0) return;
+        if (line[lineLength-2] == '\r') line[lineLength-2] = '\0';
+        return;
+    }
+    if (line[lineLength-1] == '\r') line[lineLength-1] = '\0';
+}
+
+/*
+ * Returns the index of the matching close bracket in words.
+ *
+ * @param words       expression words
+ * @param beginIndex  beginning index in words, inclusive; must be index of
+ *                    open bracket to match
+ * @param endIndex    ending index in words, exclusive
+ *
+ * @return index of matching close bracket found; a negative value if not
+ *         found
+ */
+static int
+findMatchingCloseBracket(const char * const words[], int beginIndex, int endIndex)
+{
+    int nestingCount;
+    int i;
+
+    if (strcmp(words[beginIndex], "[") != 0) return -1;
+    nestingCount = 0;
+    for (i = beginIndex + 1; i < endIndex; i++) {
+        if (strcmp(words[i], "]") == 0) {
+            if (nestingCount == 0) return i;
+            nestingCount--;
+        } else if (strcmp(words[i], "[") == 0) {
+            nestingCount++;
+        }
+    }
+    return -1;
+}
+
+/*
+ * Returns whether the if-statement numeric binary operator expression
+ * evaluates to true.
+ *
+ * @param words       expression words
+ * @param beginIndex  beginning index in words, inclusive
+ * @param fileName    name of file containing expression
+ * @param lineNum     line number in fileName where expression occurs
+ *
+ * @return a nonzero positive value if the expression is true; zero if the
+ *         expression is false; a negative value if an error occurred
+ */
+static int
+evaluateIfExpressionNumericBinaryOperator(const char * const words[], int beginIndex,
+        const char *fileName, int lineNum)
+{
+    char *strtolEndPointer;
+    long leftOperand;
+    long rightOperand;
+
+    strtolEndPointer = NULL;
+    leftOperand = strtol(words[beginIndex], &strtolEndPointer, 0);
+    if (*words[beginIndex] == '\0' || *strtolEndPointer != '\0') {
+        showError(fileName, lineNum, "Syntax error: left operand \"%s\" of \"%s\" not an integer",
+            words[beginIndex], words[beginIndex+1]);
+        return -1;
+    }
+    strtolEndPointer = NULL;
+    rightOperand = strtol(words[beginIndex+2], &strtolEndPointer, 0);
+    if (*words[beginIndex+2] == '\0' || *strtolEndPointer != '\0') {
+        showError(fileName, lineNum, "Syntax error: right operand \"%s\" of \"%s\" not an integer",
+            words[beginIndex+2], words[beginIndex+1]);
+        return -1;
+    }
+
+    if (strcmp(words[beginIndex+1], "eq") == 0) {
+        return (leftOperand == rightOperand) ? 1 : 0;
+    } else if (strcmp(words[beginIndex+1], "ne") == 0) {
+        return (leftOperand != rightOperand) ? 1 : 0;
+    } else if (strcmp(words[beginIndex+1], "gt") == 0) {
+        return (leftOperand > rightOperand) ? 1 : 0;
+    } else if (strcmp(words[beginIndex+1], "ge") == 0) {
+        return (leftOperand >= rightOperand) ? 1 : 0;
+    } else if (strcmp(words[beginIndex+1], "lt") == 0) {
+        return (leftOperand < rightOperand) ? 1 : 0;
+    } else if (strcmp(words[beginIndex+1], "le") == 0) {
+        return (leftOperand <= rightOperand) ? 1 : 0;
+    } else {
+        showError(fileName, lineNum, "Syntax error: operator \"%s\" unknown", words[beginIndex+1]);
+        return -1;
+    }
+}
+
+/*
+ * Returns whether the if-statement expression evaluates to true.
+ *
+ * @param words       expression words
+ * @param beginIndex  beginning index in words, inclusive
+ * @param endIndex    ending index in words, exclusive
+ * @param fileName    name of file containing expression
+ * @param lineNum     line number in fileName where expression occurs
+ *
+ * @return a nonzero positive value if the expression is true; zero if the
+ *         expression is false; a negative value if an error occurred
+ */
+static int
+evaluateIfExpression(const char * const words[], int beginIndex, int endIndex, const char *fileName,
+        int lineNum)
+{
+    int i;
+    int result;
+    int closeBracketIndex;
+
+    if (beginIndex >= endIndex) {
+        showError(fileName, lineNum, "Syntax error: empty expression");
+        return -1;
+    }
+    i = beginIndex;
+    result = -1;
+    while (i < endIndex) {
+        if (strcmp(words[i], "[") == 0) {
+            closeBracketIndex = findMatchingCloseBracket(words, i, endIndex);
+            if (closeBracketIndex < 0) {
+                showError(fileName, lineNum, "Syntax error: no matching \"]\"");
+                return -1;
+            }
+            result = evaluateIfExpression(words, i + 1, closeBracketIndex, fileName, lineNum);
+            if (result < 0) return result;
+            i = closeBracketIndex + 1;
+        } else if (strcmp(words[i], "&&") == 0) {
+            if (result < 0) {
+                showError(fileName, lineNum, "Syntax error: \"&&\" unexpected");
+                return -1;
+            }
+            if (!result) return 0;
+            i++;
+        } else if (strcmp(words[i], "||") == 0) {
+            if (result < 0) {
+                showError(fileName, lineNum, "Syntax error: \"||\" unexpected");
+                return -1;
+            }
+            if (result) return 1;
+            i++;
+        } else if (endIndex - i >= 3) {
+            if (strcmp(words[i+1], "=") == 0) {
+                result = (strcmp(words[i], words[i+2]) == 0) ? 1 : 0;
+            } else if (strcmp(words[i+1], "!=") == 0) {
+                result = (strcmp(words[i], words[i+2]) != 0) ? 1 : 0;
+            } else {
+                result = evaluateIfExpressionNumericBinaryOperator(words, i, fileName, lineNum);
+                if (result < 0) return result;
+            }
+            i += 3;
+        } else {
+            showError(fileName, lineNum,
+                "Syntax error: expected binary operator expression instead of \"%s%s%s\"",
+                words[i],
+                (endIndex - i > 1) ? " " : "",
+                (endIndex - i > 1) ? words[i+1] : "");
+            return -1;
+        }
+    }
+    return result;
+}
+
+/*
  * "help" command
  */
 static const iocshArg helpArg0 = { "[command ...]",iocshArgArgv};
@@ -457,7 +676,7 @@
  * The body of the command interpreter
  */
 static int
-iocshBody (const char *pathname, const char *commandLine)
+iocshBody (const char *pathname, const char *commandLines)
 {
     FILE *fp = NULL;
     const char *filename = NULL;
@@ -481,11 +700,20 @@
     struct iocshFuncDef const *piocshFuncDef;
     void *readlineContext = NULL;
     int wasOkToBlock;
+    char *commandLine = NULL;
+    size_t commandLineLength = 0;
+    int commandLinesBeginIndex = -1;
+    int commandLinesNextBeginIndex = -1;
+    enum IfStatementState { IfStateReadToElifOrElseOrEndif, IfStateSkipToElifOrElseOrEndif,
+        IfStateReadToEndif, IfStateSkipToEndif };
+    enum IfStatementState ifStmtStack[IF_STATEMENT_STACK_CAPACITY];
+    int ifStmtStackSize = 0;
+    int expressionValue = 0;
     
     /*
      * See if command interpreter is interactive
      */
-    if (commandLine == NULL) {
+    if (commandLines == NULL) {
         if ((pathname == NULL) || (strcmp (pathname, "<telnet>") == 0)) {
             if ((prompt = envGetConfigParamPtr(&IOCSH_PS1)) == NULL)
                 prompt = "epics> ";
@@ -533,9 +761,24 @@
         /*
          * Read a line
          */
-        if (commandLine) {
-            if (raw != NULL)
-                break;
+        if (commandLines) {
+            free(commandLine);
+            commandLine = NULL;
+            commandLinesBeginIndex = findLineBeginning(commandLines, commandLinesBeginIndex);
+            if (commandLinesBeginIndex < 0)
+                break;
+            commandLinesNextBeginIndex = findLineBeginning(commandLines, commandLinesBeginIndex);
+            commandLineLength = (commandLinesNextBeginIndex < 0)
+                ? strlen(commandLines + commandLinesBeginIndex)
+                : commandLinesNextBeginIndex - commandLinesBeginIndex;
+            commandLine = (char *)malloc((commandLineLength + 1) * sizeof(commandLines[0]));
+            if (commandLine == NULL) {
+                printf("Out of memory!\n");
+                break;
+            }
+            strncpy(commandLine, commandLines + commandLinesBeginIndex, commandLineLength);
+            commandLine[commandLineLength] = '\0';
+            removeLineTerminator(commandLine, commandLineLength);
             raw = commandLine;
         }
         else {
@@ -549,7 +792,7 @@
          * them if they came from a script.
          */
         if (*raw == '#') {
-            if ((prompt == NULL) && (commandLine == NULL))
+            if ((prompt == NULL) && (commandLines == NULL))
                 puts(raw);
             continue;
         }
@@ -562,9 +805,17 @@
             continue;
 
         /*
+         * Free commandLine since will use line from now on
+         */
+        if (commandLines != NULL) {
+            free(commandLine);
+            commandLine = NULL;
+        }
+
+        /*
          * Echo commands read from scripts
          */
-        if ((prompt == NULL) && *line && (commandLine == NULL))
+        if ((prompt == NULL) && *line && (commandLines == NULL))
             puts(line);
 
         /*
@@ -695,6 +946,101 @@
         argv[argc] = NULL;
 
         /*
+         * Handle reserved words
+         */
+        if (argc) {
+             /*
+              * if-statement
+              */
+             if (strcmp(argv[0], "if") == 0) {
+                 if (ifStmtStackSize == IF_STATEMENT_STACK_CAPACITY) {
+                     showError(filename, lineno,
+                         "Syntax error: max if-statement nesting level (%d) reached",
+                         IF_STATEMENT_STACK_CAPACITY);
+                     break;
+                 }
+                 if (ifStmtStackSize != 0 &&
+                         (ifStmtStack[ifStmtStackSize-1] == IfStateSkipToElifOrElseOrEndif ||
+                             ifStmtStack[ifStmtStackSize-1] == IfStateSkipToEndif)) {
+                     ifStmtStack[ifStmtStackSize] = IfStateSkipToEndif;
+                     ifStmtStackSize++;
+                     continue;
+                 }
+                 expressionValue = evaluateIfExpression(argv, 1, argc, filename, lineno);
+                 if (expressionValue < 0) {
+                     ifStmtStack[ifStmtStackSize] = IfStateSkipToEndif;
+                 } else if (expressionValue) {
+                     ifStmtStack[ifStmtStackSize] = IfStateReadToElifOrElseOrEndif;
+                 } else {
+                     ifStmtStack[ifStmtStackSize] = IfStateSkipToElifOrElseOrEndif;
+                 }
+                 ifStmtStackSize++;
+                 continue;
+             } else if (strcmp(argv[0], "elif") == 0) {
+                 if (ifStmtStackSize == 0) {
+                     showError(filename, lineno, "Syntax error: \"elif\" unexpected");
+                     continue;
+                 }
+                 if (ifStmtStack[ifStmtStackSize-1] == IfStateReadToEndif) {
+                     showError(filename, lineno, "Syntax error: \"elif\" unexpected");
+                     continue;
+                 }
+                 if (ifStmtStack[ifStmtStackSize-1] == IfStateSkipToEndif) {
+                     continue;
+                 }
+                 if (ifStmtStack[ifStmtStackSize-1] == IfStateReadToElifOrElseOrEndif) {
+                     ifStmtStack[ifStmtStackSize-1] = IfStateSkipToEndif;
+                     continue;
+                 }
+                 expressionValue = evaluateIfExpression(argv, 1, argc, filename, lineno);
+                 if (expressionValue < 0) {
+                     ifStmtStack[ifStmtStackSize-1] = IfStateSkipToEndif;
+                 } else if (expressionValue) {
+                     ifStmtStack[ifStmtStackSize-1] = IfStateReadToElifOrElseOrEndif;
+                 } else {
+                     ifStmtStack[ifStmtStackSize-1] = IfStateSkipToElifOrElseOrEndif;
+                 }
+                 continue;
+             } else if (strcmp(argv[0], "else") == 0) {
+                 if (ifStmtStackSize == 0) {
+                     showError(filename, lineno, "Syntax error: \"else\" unexpected");
+                     continue;
+                 }
+                 if (ifStmtStack[ifStmtStackSize-1] == IfStateReadToEndif) {
+                     showError(filename, lineno, "Syntax error: \"else\" unexpected");
+                     continue;
+                 }
+                 if (argc != 1) {
+                     showError(filename, lineno, "Syntax error: unexpected word after \"else\"");
+                 }
+                 if (ifStmtStack[ifStmtStackSize-1] == IfStateSkipToEndif) {
+                     continue;
+                 }
+                 if (ifStmtStack[ifStmtStackSize-1] == IfStateReadToElifOrElseOrEndif) {
+                     ifStmtStack[ifStmtStackSize-1] = IfStateSkipToEndif;
+                     continue;
+                 }
+                 ifStmtStack[ifStmtStackSize-1] = IfStateReadToEndif;
+                 continue;
+             } else if (strcmp(argv[0], "endif") == 0) {
+                 if (ifStmtStackSize == 0) {
+                     showError(filename, lineno, "Syntax error: \"endif\" unexpected");
+                     continue;
+                 }
+                 if (argc != 1) {
+                     showError(filename, lineno, "Syntax error: unexpected word after \"endif\"");
+                 }
+                 ifStmtStackSize--;
+                 continue;
+             } else if (ifStmtStackSize != 0) {
+                 if (ifStmtStack[ifStmtStackSize-1] == IfStateSkipToElifOrElseOrEndif ||
+                         ifStmtStack[ifStmtStackSize-1] == IfStateSkipToEndif) {
+                     continue;
+                 }
+             }
+        }
+
+        /*
          * Special case -- Redirected input but no command
          * Treat as if 'iocsh filename'.
          */

=== modified file 'src/libCom/test/Makefile'
--- src/libCom/test/Makefile	2011-10-28 20:19:54 +0000
+++ src/libCom/test/Makefile	2012-01-09 18:16:27 +0000
@@ -152,6 +152,11 @@
 testHarness_SRCS += epicsMessageQueueTest.cpp
 TESTS += epicsMessageQueueTest
 
+TESTPROD_HOST += iocshTest
+iocshTest_SRCS += iocshTest.c
+testHarness_SRCS += iocshTest.c
+TESTS += iocshTest
+
 
 # The testHarness runs all the test programs in a known working order.
 testHarness_SRCS += epicsRunLibComTests.c

=== modified file 'src/libCom/test/epicsTimeTest.cpp'
--- src/libCom/test/epicsTimeTest.cpp	2007-05-07 20:50:38 +0000
+++ src/libCom/test/epicsTimeTest.cpp	2012-01-09 18:16:27 +0000
@@ -9,6 +9,11 @@
 /*
  * Authors: Jeff Hill, Marty Kraimer and Andrew Johnson
  */
+ 
+#ifdef __SUNPRO_CC
+using namespace std;
+#endif
+
 #include <cstddef>
 #include <cstdio>
 #include <ctime>

=== added file 'src/libCom/test/iocshTest.c'
--- src/libCom/test/iocshTest.c	1970-01-01 00:00:00 +0000
+++ src/libCom/test/iocshTest.c	2012-01-09 18:16:27 +0000
@@ -0,0 +1,840 @@
+#include "envDefs.h"
+#include "iocsh.h"
+
+#include "epicsUnitTest.h"
+#include "testMain.h"
+
+#define IOCSH_TEST_PROGRAM_VARS_SIZE 8
+
+static int iocshTestProgramVars[IOCSH_TEST_PROGRAM_VARS_SIZE];
+
+static void initializeIocshTestProgramVars(void)
+{
+    int i;
+
+    for (i = 0; i < IOCSH_TEST_PROGRAM_VARS_SIZE; i++) {
+        iocshTestProgramVars[i] = 0;
+    }
+}
+
+static const iocshArg setIocshTestProgramVarArg0 = {"index", iocshArgInt};
+static const iocshArg setIocshTestProgramVarArg1 = {"value", iocshArgInt};
+static const iocshArg * const setIocshTestProgramVarArgs[2] =
+    {&setIocshTestProgramVarArg0, &setIocshTestProgramVarArg1};
+static const iocshFuncDef setIocshTestProgramVarFuncDef =
+    {"setIocshTestProgramVar", 2, setIocshTestProgramVarArgs};
+static void setIocshTestProgramVarCallFunc(const iocshArgBuf *args)
+{
+    iocshTestProgramVars[args[0].ival] = args[1].ival;
+}
+
+MAIN(iocshTest)
+{
+    testPlan(85);
+
+    iocshRegister(&setIocshTestProgramVarFuncDef,
+        setIocshTestProgramVarCallFunc);
+
+    /*
+     * iocshCmd accepting multiple lines
+     */
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "setIocshTestProgramVar 0 1"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "iocshCmd one line, lf");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "setIocshTestProgramVar 0 1\n"
+        "setIocshTestProgramVar 1 2"
+    );
+    testOk(iocshTestProgramVars[0] == 1
+        && iocshTestProgramVars[1] == 2,
+        "iocshCmd two lines, lf");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "setIocshTestProgramVar 0 1\n"
+        "setIocshTestProgramVar 1 2\n"
+        "setIocshTestProgramVar 2 3"
+    );
+    testOk(iocshTestProgramVars[0] == 1
+        && iocshTestProgramVars[1] == 2
+        && iocshTestProgramVars[2] == 3,
+        "iocshCmd three lines, lf");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "setIocshTestProgramVar 0 1\r"
+        "setIocshTestProgramVar 1 2\r"
+        "setIocshTestProgramVar 2 3"
+    );
+    testOk(iocshTestProgramVars[0] == 1
+        && iocshTestProgramVars[1] == 2
+        && iocshTestProgramVars[2] == 3,
+        "iocshCmd three lines, cr");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "setIocshTestProgramVar 0 1\r\n"
+        "setIocshTestProgramVar 1 2\r\n"
+        "setIocshTestProgramVar 2 3"
+    );
+    testOk(iocshTestProgramVars[0] == 1
+        && iocshTestProgramVars[1] == 2
+        && iocshTestProgramVars[2] == 3,
+        "iocshCmd three lines, cr-lf");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "setIocshTestProgramVar 0 1\r"
+        "setIocshTestProgramVar 1 2\n"
+        "setIocshTestProgramVar 2 3"
+    );
+    testOk(iocshTestProgramVars[0] == 1
+        && iocshTestProgramVars[1] == 2
+        && iocshTestProgramVars[2] == 3,
+        "iocshCmd three lines, cr and lf");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "setIocshTestProgramVar 0 1\r"
+        "setIocshTestProgramVar 1 2\r\n"
+        "setIocshTestProgramVar 2 3"
+    );
+    testOk(iocshTestProgramVars[0] == 1
+        && iocshTestProgramVars[1] == 2
+        && iocshTestProgramVars[2] == 3,
+        "iocshCmd three lines, cr and cr-lf");
+
+    /*
+     * if-statement
+     */
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if false");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "else\n"
+        "  setIocshTestProgramVar 1 2\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1
+        && iocshTestProgramVars[1] == 0,
+        "if-else true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "else\n"
+        "  setIocshTestProgramVar 1 2\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0
+        && iocshTestProgramVars[1] == 2,
+        "if-else false");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "elif a = a\n"
+        "  setIocshTestProgramVar 1 2\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1
+        && iocshTestProgramVars[1] == 0,
+        "if-elif true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "elif a = a\n"
+        "  setIocshTestProgramVar 1 2\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0
+        && iocshTestProgramVars[1] == 2,
+        "if-elif false-true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "elif a = a\n"
+        "  setIocshTestProgramVar 1 2\n"
+        "else\n"
+        "  setIocshTestProgramVar 2 3\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0
+        && iocshTestProgramVars[1] == 2
+        && iocshTestProgramVars[2] == 0,
+        "if-elif-else false-true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "elif a = c\n"
+        "  setIocshTestProgramVar 1 2\n"
+        "else\n"
+        "  setIocshTestProgramVar 2 3\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0
+        && iocshTestProgramVars[1] == 0
+        && iocshTestProgramVars[2] == 3,
+        "if-elif-else false-false");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "elif a = c\n"
+        "  setIocshTestProgramVar 1 2\n"
+        "elif a = a\n"
+        "  setIocshTestProgramVar 2 3\n"
+        "else\n"
+        "  setIocshTestProgramVar 3 4\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0
+        && iocshTestProgramVars[1] == 0
+        && iocshTestProgramVars[2] == 3
+        && iocshTestProgramVars[3] == 0,
+        "if-elif-elif-else false-false-true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a\n"
+        "  if a = a\n"
+        "    setIocshTestProgramVar 0 1\n"
+        "  endif\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if-if true-true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a\n"
+        "  if a = b\n"
+        "    setIocshTestProgramVar 0 1\n"
+        "  endif\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if-if true-false");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b\n"
+        "  if a = a\n"
+        "    setIocshTestProgramVar 0 1\n"
+        "  endif\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if-if false-true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a\n"
+        "  if a = a\n"
+        "    setIocshTestProgramVar 0 1\n"
+        "  else\n"
+        "    setIocshTestProgramVar 1 2\n"
+        "  endif\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1
+        && iocshTestProgramVars[1] == 0,
+        "if-if-else true-true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a\n"
+        "  if a = b\n"
+        "    setIocshTestProgramVar 0 1\n"
+        "  else\n"
+        "    setIocshTestProgramVar 1 2\n"
+        "  endif\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0
+        && iocshTestProgramVars[1] == 2,
+        "if-if-else true-false");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b\n"
+        "  if a = a\n"
+        "    setIocshTestProgramVar 0 1\n"
+        "  else\n"
+        "    setIocshTestProgramVar 1 2\n"
+        "  endif\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0
+        && iocshTestProgramVars[1] == 0,
+        "if-if-else false-true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a\n"
+        "  if a = a\n"
+        "    if a = a\n"
+        "      setIocshTestProgramVar 0 1\n"
+        "    endif\n"
+        "  endif\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if-if-if true-true-true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a\n"
+        "  if a = a\n"
+        "    if a = b\n"
+        "      setIocshTestProgramVar 0 1\n"
+        "    endif\n"
+        "  endif\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if-if-if true-true-false");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b\n"
+        "  if a = a\n"
+        "    if a = a\n"
+        "      setIocshTestProgramVar 0 1\n"
+        "    endif\n"
+        "  endif\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if-if-if false-true-true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b\n"
+        "  if a = b\n"
+        "    if a = a\n"
+        "      setIocshTestProgramVar 0 1\n"
+        "    endif\n"
+        "  endif\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if-if-if false-false-true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b\n"
+        "  if a = a\n"
+        "    if a = a\n"
+        "      setIocshTestProgramVar 0 1\n"
+        "    endif\n"
+        "  endif\n"
+        "else\n"
+        "  setIocshTestProgramVar 1 2\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0
+        && iocshTestProgramVars[1] == 2,
+        "if-if-if false-false-true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a\n"
+        "  if a = b\n"
+        "    setIocshTestProgramVar 0 1\n"
+        "  elif a = a\n"
+        "    setIocshTestProgramVar 1 2\n"
+        "  endif\n"
+        "else\n"
+        "  setIocshTestProgramVar 2 3\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0
+        && iocshTestProgramVars[1] == 2
+        && iocshTestProgramVars[2] == 0,
+        "if-if-elif-else true-false-true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if red = red\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "\"=\" operator true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if red = blue\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "\"=\" operator false");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 1 = 1\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if 1 = 1, string compare");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 01 = 1\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if 01 = 1, string compare");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 1.0 = 1\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if 1.0 = 1, string compare");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 1.0 = 1.00\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if 1.0 = 1.00, string compare");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 1 = 0x1\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if 1 = 0x1, string compare");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if red != red\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "\"!=\" operator false");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if red != blue\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "\"!=\" operator true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 1.0 != 1.00\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if 1.0 != 1.00, string compare");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 eq 3\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if 3 eq 3");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 eq 4\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if 3 eq 4");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 eq 0x3\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if 3 eq 0x3");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 ne 3\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if 3 ne 3");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 ne 4\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if 3 ne 4");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 ne 0x3\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if 3 eq 0x3");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 gt 2\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if 3 gt 2");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 gt 3\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if 3 gt 3");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 gt 4\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if 3 gt 4");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 ge 2\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if 3 ge 2");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 ge 3\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if 3 ge 3");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 ge 4\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if 3 ge 4");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 lt 2\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if 3 lt 2");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 lt 3\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if 3 lt 3");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 lt 4\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if 3 lt 4");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 le 2\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if 3 le 2");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 le 3\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if 3 le 3");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if 3 le 4\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if 3 le 4");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a && b = b\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if true && true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a && b = c\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if true && false");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b && c = c\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if false && true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a && b = b && c = c\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if true && true && true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a && b = b && c = d\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if true && true && false");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b && c = d && e = f\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if false && false && false");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a || b = b\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if true || true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a || b = c\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if true || false");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b || c = c\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if false || true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a || b = b || c = c\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if true || true || true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b || c = c || d = d\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if false || true || true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b || c = d || e = f\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if false || false || false");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if [ a = a ]\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if [ true ]");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if [ a = b ]\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if [ false ]");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if [ [ a = a ] ]\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if [ [ true ] ]");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a && [ b = b ]\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if true && [ true ]");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a && [ b = c ]\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if true && [ false ]");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if [ a = a ] && b = b\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if [ true ] && true");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if [ a = a ] && b = c\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if [ true ] && false");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if [ a = a ] && [ b = b ]\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if [ true ] && [ true ]");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if [ a = a ] && [ b = c ]\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if [ true ] && [ false ]");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if [ a = a && b = b ] || [ c = c && d = d ]\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if [ T && T ] || [ T && T ]");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if [ a = a && b = c ] || [ d = d && e = e ]\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if [ T && F ] || [ T && T ]");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = a && [ b = c || d = d ]\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if T && [ F || T ]");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b || [ c = d || [ e = e ] ]\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if F || [ F || [ T ] ]");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b || c = c && d = d\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if F || T && T");
+
+    initializeIocshTestProgramVars();
+    iocshCmd(
+        "if a = b || c = c && d = e\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if F || T && F");
+
+    initializeIocshTestProgramVars();
+    epicsEnvSet("IOCSH_TEST_PROGRAM_VAR", "Y");
+    iocshCmd(
+        "if ${IOCSH_TEST_PROGRAM_VAR} = Y\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 1, "if true env var substitution");
+
+    initializeIocshTestProgramVars();
+    epicsEnvSet("IOCSH_TEST_PROGRAM_VAR", "N");
+    iocshCmd(
+        "if ${IOCSH_TEST_PROGRAM_VAR} = Y\n"
+        "  setIocshTestProgramVar 0 1\n"
+        "endif"
+    );
+    testOk(iocshTestProgramVars[0] == 0, "if false env var substitution");
+
+    return testDone();
+}

=== modified file 'src/tools/makeDbDepends.pl'
--- src/tools/makeDbDepends.pl	2011-06-08 17:26:01 +0000
+++ src/tools/makeDbDepends.pl	2012-01-09 18:16:27 +0000
@@ -14,8 +14,8 @@
 my %depends;
 
 while (my $line = <>) {
-    $depends{$2}++ if $line =~ m/^\s*file\s*(["']?)(.*)\1/;
-    $depends{$1}++ if $line =~ m/^\s*include\s+"(.*)"/;
+    $depends{$2}++ if $line =~ m/^ \s* file \s* (["']?) (\S*) \1 /x;
+    $depends{$1}++ if $line =~ m/^ \s* include \s* "(.*)" /x;
 }
 
 if (%depends) {


Replies:
Re: [Merge] lp:~jlmuir/epics-base/iocsh-if-flow-control-3.14 into lp:epics-base Andrew Johnson
Re: [Merge] lp:~jlmuir/epics-base/iocsh-if-flow-control-3.14 into lp:epics-base Andrew Johnson
[Merge] lp:~jlmuir/epics-base/iocsh-if-flow-control-3.14 into lp:epics-base Andrew Johnson

Navigate by Date:
Prev: [Merge] lp:~jlmuir/epics-base/iocsh-if-flow-control-3.14 into lp:epics-base J. Lewis Muir
Next: Re: [Merge] lp:~jlmuir/epics-base/iocsh-if-flow-control-3.14 into lp:epics-base Andrew Johnson
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  <20122013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: [Merge] lp:~jlmuir/epics-base/iocsh-if-flow-control-3.14 into lp:epics-base J. Lewis Muir
Next: Re: [Merge] lp:~jlmuir/epics-base/iocsh-if-flow-control-3.14 into lp:epics-base Andrew Johnson
Index: 2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  <20122013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024