add condition negation

git-svn-id: https://svn.apache.org/repos/asf/ant/antlibs/props/trunk@916485 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/docs/index.html b/docs/index.html
index c054cee..571ed49 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -128,9 +128,10 @@
             attempts to invoke an Ant condition of the given name
             setting the given attibute values and evaluates to either
             Boolean.TRUE or Boolean.FALSE.  Usage looks
-            like <em>${os(family=unix)}</em>.  This is probably most
-            useful together with the if/unless attributes of tasks or
-            targets.</td>
+            like <em>${os(family=unix)}</em> / <em>${!os(family=unix)}</em>.
+            This is probably most useful together with the
+            <code>if</code>/<code>unless</code> attributes of tasks or targets.
+        </td>
       </tr>
       <tr>
         <a name="encodeURL" />
diff --git a/src/main/org/apache/ant/props/ConditionEvaluator.java b/src/main/org/apache/ant/props/ConditionEvaluator.java
index 8fcb4f8..998988d 100644
--- a/src/main/org/apache/ant/props/ConditionEvaluator.java
+++ b/src/main/org/apache/ant/props/ConditionEvaluator.java
@@ -44,7 +44,7 @@
      * Create a new ConditionEvaluator instance.
      */
     public ConditionEvaluator() {
-        super("^(.+?)\\(((?:(?:.+?)=(?:.+?))?(?:,(?:.+?)=(?:.+?))*?)\\)$");
+        super("^(!)?(.+?)\\(((?:(?:.+?)=(?:.+?))?(?:,(?:.+?)=(?:.+?))*?)\\)$");
     }
 
     /**
@@ -52,9 +52,13 @@
      */
     protected Object evaluate(String[] groups, PropertyHelper propertyHelper) {
         Project p = propertyHelper.getProject();
-        Condition cond = createCondition(p, groups[1]);
+        boolean negate = false;
+        if ("!".equals(groups[1])) {
+            negate = true;
+        }
+        Condition cond = createCondition(p, groups[2]);
         if (cond != null) {
-            if (groups[2].length() > 0) {
+            if (groups[3].length() > 0) {
                 Object realObject = TypeAdapter.class.isInstance(cond) ? ((TypeAdapter) cond)
                         .getProxy() : cond;
                 if (realObject == null) {
@@ -62,13 +66,13 @@
                             "Found null proxy object for adapted condition " + cond.toString());
                 }
                 IntrospectionHelper ih = IntrospectionHelper.getHelper(realObject.getClass());
-                String[] attributes = COMMA.split(groups[2]);
+                String[] attributes = COMMA.split(groups[3]);
                 for (int i = 0; i < attributes.length; i++) {
                     String[] keyValue = EQ.split(attributes[i]);
                     ih.setAttribute(p, realObject, keyValue[0].trim(), keyValue[1].trim());
                 }
             }
-            return Boolean.valueOf(cond.eval());
+            return Boolean.valueOf(cond.eval() ^ negate);
         }
         return null;
     }
diff --git a/src/tests/antunit/condition-test.xml b/src/tests/antunit/condition-test.xml
index 51a7e38..984e911 100644
--- a/src/tests/antunit/condition-test.xml
+++ b/src/tests/antunit/condition-test.xml
@@ -99,4 +99,11 @@
     </antunit>
   </target>
 
+  <target name="testNegation">
+    <property name="foo" value="false" />
+    <au:assertTrue>
+      <istrue value="${!istrue(value=${foo})}" />
+    </au:assertTrue>
+  </target>
+
 </project>