Add sorting
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1736019 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 8706153..fdd7729 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
@@ -30,11 +30,13 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.PatternSyntaxException;
+import java.util.stream.Collector;
import java.util.stream.Collectors;
@SuppressWarnings("fallthrough")
@@ -634,18 +636,44 @@
{
getch();
+ // sort flags
+ boolean flago = false;
+ boolean flagO = false;
+ boolean flaga = false;
+ boolean flagi = false;
+ boolean flagn = false;
+ // map flags
boolean flagk = false;
boolean flagv = false;
+ // param flags
boolean flagP = false;
+ // case transformation flags
boolean flagC = false;
boolean flagL = false;
boolean flagU = false;
+ // pattern flags
boolean flagG = false;
+ // expand flag
boolean flagExpand = false;
if (ch == '(') {
getch();
while (ch != EOT && ch != ')') {
switch (ch) {
+ case 'o':
+ flago = true;
+ break;
+ case 'O':
+ flagO = true;
+ break;
+ case 'a':
+ flaga = true;
+ break;
+ case 'i':
+ flagi = true;
+ break;
+ case 'n':
+ flagn = true;
+ break;
case 'P':
flagP = true;
break;
@@ -930,6 +958,88 @@
}
}
+ if (val instanceof Collection && (flaga || flagi || flagn || flago || flagO)) {
+ List<Object> list;
+ if (flagn) {
+ boolean insensitive = flagi;
+ Comparator<String> comparator = (s1, s2) -> {
+ int i1s = 0, i2s = 0;
+ while (i1s < s1.length() && i2s < s2.length()) {
+ char c1 = s1.charAt(i1s);
+ char c2 = s2.charAt(i2s);
+ if (insensitive) {
+ c1 = Character.toLowerCase(c1);
+ c2 = Character.toLowerCase(c2);
+ }
+ if (c1 != c2) {
+ if (c1 >= '0' && c1 <= '9' && c2 >= '0' && c2 <= '9') {
+ break;
+ } else {
+ return c1 < c2 ? -1 : 1;
+ }
+ }
+ i1s++;
+ i2s++;
+ }
+ while (i1s > 0) {
+ char c1 = s1.charAt(i1s-1);
+ if (c1 < '0' || c1 > '9') {
+ break;
+ }
+ i1s--;
+ }
+ while (i2s > 0) {
+ char c2 = s2.charAt(i2s-1);
+ if (c2 < '0' || c2 > '9') {
+ break;
+ }
+ i2s--;
+ }
+ int i1e = i1s;
+ int i2e = i2s;
+ while (i1e < s1.length() - 1) {
+ char c1 = s1.charAt(i1e+1);
+ if (c1 < '0' || c1 > '9') {
+ break;
+ }
+ i1e++;
+ }
+ while (i2e < s2.length() - 1) {
+ char c2 = s2.charAt(i2e+1);
+ if (c2 < '0' || c2 > '9') {
+ break;
+ }
+ i2e++;
+ }
+ int i1 = Integer.parseInt(s1.substring(i1s, i1e + 1));
+ int i2 = Integer.parseInt(s2.substring(i2s, i2e + 1));
+ if (i1 < i2) {
+ return -1;
+ } else if (i1 > i2) {
+ return 1;
+ } else {
+ return i1e > i2e ? -1 : 1;
+ }
+ };
+ list = ((Collection<Object>) val).stream()
+ .map(String::valueOf)
+ .sorted(comparator)
+ .collect(Collectors.toList());
+ } else if (flaga) {
+ list = new ArrayList<>((Collection<Object>) val);
+ } else {
+ Comparator<String> comparator = flagi ? String.CASE_INSENSITIVE_ORDER : Comparator.naturalOrder();
+ list = ((Collection<Object>) val).stream()
+ .map(String::valueOf)
+ .sorted(comparator)
+ .collect(Collectors.toList());
+ }
+ if (flagO) {
+ Collections.reverse(list);
+ }
+ val = list;
+ }
+
if (inQuote) {
if (val instanceof Map) {
val = toList((Map) val, flagk, flagv);
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 fae2753..61459ab 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,25 @@
}
@Test
+ public void testSorting() throws Exception {
+ vars.clear();
+ vars.put("array", Arrays.asList("foo1", "foo02", "foo2", "fOo3", "Foo20", "foo23"));
+
+ assertEquals(Arrays.asList("Foo20", "fOo3", "foo02", "foo1", "foo2", "foo23"), expand("${(o)array}"));
+ assertEquals(Arrays.asList("foo23", "foo2", "foo1", "foo02", "fOo3", "Foo20"), expand("${(O)array}"));
+ assertEquals(Arrays.asList("foo02", "foo1", "foo2", "Foo20", "foo23", "fOo3"), expand("${(oi)array}"));
+ assertEquals(Arrays.asList("fOo3", "foo23", "Foo20", "foo2", "foo1", "foo02"), expand("${(Oi)array}"));
+ assertEquals(Arrays.asList("foo1", "foo02", "foo2", "fOo3", "Foo20", "foo23"), expand("${(oa)array}"));
+ assertEquals(Arrays.asList("foo23", "Foo20", "fOo3", "foo2", "foo02", "foo1"), expand("${(Oa)array}"));
+ assertEquals(Arrays.asList("foo1", "foo02", "foo2", "fOo3", "Foo20", "foo23"), expand("${(oia)array}"));
+ assertEquals(Arrays.asList("foo23", "Foo20", "fOo3", "foo2", "foo02", "foo1"), expand("${(Oia)array}"));
+ assertEquals(Arrays.asList("Foo20", "fOo3", "foo1", "foo02", "foo2", "foo23"), expand("${(on)array}"));
+ assertEquals(Arrays.asList("foo23", "foo2", "foo02", "foo1", "fOo3", "Foo20"), expand("${(On)array}"));
+ assertEquals(Arrays.asList("foo1", "foo02", "foo2", "fOo3", "Foo20", "foo23"), expand("${(oin)array}"));
+ assertEquals(Arrays.asList("foo23", "Foo20", "fOo3", "foo2", "foo02", "foo1"), expand("${(Oin)array}"));
+ }
+
+ @Test
public void testPatterns() throws Exception {
vars.clear();
vars.put("foo", "twinkle twinkle little star");