Improve pattern matching

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1736018 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Expander.java b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Expander.java
index ab48505..8706153 100644
--- a/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Expander.java
+++ b/gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Expander.java
@@ -181,7 +181,7 @@
     protected List<? extends CharSequence> generateFileNames(CharSequence arg) throws IOException {
         // Disable if currentDir is not set
         Path currentDir = evaluate.currentDir();
-        if (currentDir == null) {
+        if (currentDir == null || inQuote) {
             return Collections.singletonList(arg);
         }
         // Search for unquoted escapes
@@ -640,6 +640,7 @@
             boolean flagC = false;
             boolean flagL = false;
             boolean flagU = false;
+            boolean flagG = false;
             boolean flagExpand = false;
             if (ch == '(') {
                 getch();
@@ -651,6 +652,9 @@
                         case '@':
                             flagExpand = true;
                             break;
+                        case 'G':
+                            flagG = true;
+                            break;
                         case 'k':
                             flagk = true;
                             break;
@@ -703,7 +707,7 @@
                 }
                 else {
                     int start = index - 1;
-                    while (ch != EOT && ch != '}' && ":-+=?#%/^|*?".indexOf(ch) >= 0) {
+                    while (ch != EOT && ch != '}' && ":-+=?#%/".indexOf(ch) >= 0) {
                         getch();
                     }
                     Token op = text.subSequence(start, index - 1);
@@ -741,23 +745,45 @@
                             throw new IllegalArgumentException(name + ": parameter not set");
                         }
                     }
-                    else if (Token.eq("#", op) || Token.eq("##", op) || Token.eq("%", op) || Token.eq("%%", op)) {
+                    else if (Token.eq("#", op) || Token.eq("##", op)
+                            || Token.eq("%", op) || Token.eq("%%", op)
+                            || Token.eq("/", op) || Token.eq("//", op)) {
                         val1 = val1 instanceof Token ? evaluate.get(expand((Token) val1).toString()) : val1;
                         Object val2 = getValue();
                         if (val2 != null) {
                             String p = toRegexPattern(val2.toString(), op.length() == 1);
-                            String m = op.charAt(0) == '#' ? "^" + p : p + "$";
+                            String r;
+                            if (op.charAt(0) == '/') {
+                                if (ch == '/') {
+                                    getch();
+                                    r = getValue().toString();
+                                } else {
+                                    r = "";
+                                }
+                            } else {
+                                p = toRegexPattern(val2.toString(), op.length() == 1);
+                                r = "";
+                            }
+                            String m = op.charAt(0) == '#' ? "^" + p : op.charAt(0) == '%' ? p + "$" : p;
                             if (val1 instanceof Map) {
                                 val1 = toList((Map) val1, flagk, flagv);
                             }
                             if (val1 instanceof Collection) {
                                 List<String> l = new ArrayList<>();
                                 for (Object o : ((Collection) val1)) {
-                                    l.add(o.toString().replaceFirst(m, ""));
+                                    if (flagG) {
+                                        l.add(o.toString().replaceAll(m, r));
+                                    } else {
+                                        l.add(o.toString().replaceFirst(m, r));
+                                    }
                                 }
                                 val = l;
                             } else if (val1 != null) {
-                                val = val1.toString().replaceFirst(m, "");
+                                if (flagG) {
+                                    val = val1.toString().replaceAll(m, r);
+                                } else {
+                                    val = val1.toString().replaceFirst(m, r);
+                                }
                             }
                         } else {
                             val = val1;
diff --git a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestTokenizer.java b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestTokenizer.java
index aede37a..fae2753 100644
--- a/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestTokenizer.java
+++ b/gogo/runtime/src/test/java/org/apache/felix/gogo/runtime/TestTokenizer.java
@@ -195,6 +195,19 @@
     }
 
     @Test
+    public void testPatterns() throws Exception {
+        vars.clear();
+        vars.put("foo", "twinkle twinkle little star");
+        vars.put("sub", "t*e");
+        vars.put("rep", "spy");
+
+        assertEquals("spy twinkle little star", expand("${foo/${sub}/${rep}}"));
+        assertEquals("spy star", expand("${foo//${sub}/${rep}}"));
+        assertEquals("spy spy lispy star", expand("${(G)foo/${sub}/${rep}}"));
+        assertEquals("spy star", expand("${(G)foo//${sub}/${rep}}"));
+    }
+
+    @Test
     public void testExpand() throws Exception
     {
         final URI home = new URI("/home/derek");