in gogo/runtime/src/main/java/org/apache/felix/gogo/runtime/Expander.java [238:492]
protected List<? extends CharSequence> expandBraces(CharSequence arg) throws Exception
{
int braces = 0;
boolean escaped = false;
boolean doubleQuoted = false;
boolean singleQuoted = false;
List<CharSequence> parts = new ArrayList<>();
int start = 0;
for (int i = 0; i < arg.length(); i++)
{
char c = arg.charAt(i);
if (doubleQuoted && escaped)
{
escaped = false;
}
else if (escaped)
{
escaped = false;
}
else if (singleQuoted)
{
if (c == '\'')
{
singleQuoted = false;
}
}
else if (doubleQuoted)
{
if (c == '\\')
{
escaped = true;
}
else if (c == '\"')
{
doubleQuoted = false;
}
}
else if (c == '\\')
{
escaped = true;
}
else if (c == '\'')
{
singleQuoted = true;
}
else if (c == '"')
{
doubleQuoted = true;
}
else
{
if (c == '{')
{
if (braces++ == 0)
{
if (i > start)
{
parts.add(arg.subSequence(start, i));
}
start = i;
}
}
else if (c == '}')
{
if (--braces == 0)
{
parts.add(arg.subSequence(start, i + 1));
start = i + 1;
}
}
}
}
if (start < arg.length())
{
parts.add(arg.subSequence(start, arg.length()));
}
if (start == 0)
{
return Collections.singletonList(arg);
}
List<CharSequence> generated = new ArrayList<>();
Pattern pattern = Pattern.compile(
"\\{(((?<intstart>\\-?[0-9]+)\\.\\.(?<intend>\\-?[0-9]+)(\\.\\.(?<intinc>\\-?0*[1-9][0-9]*))?)" +
"|((?<charstart>\\S)\\.\\.(?<charend>\\S)))\\}");
for (CharSequence part : parts)
{
List<CharSequence> generators = new ArrayList<>();
Matcher matcher = pattern.matcher(part);
if (matcher.matches())
{
if (matcher.group("intstart") != null)
{
int intstart = Integer.parseInt(matcher.group("intstart"));
int intend = Integer.parseInt(matcher.group("intend"));
int intinc = matcher.group("intinc") != null ? Integer.parseInt(matcher.group("intinc")) : 1;
if (intstart > intend)
{
if (intinc < 0)
{
int k = intstart;
intstart = intend;
intend = k;
}
intinc = -intinc;
}
else
{
if (intinc < 0)
{
int k = intstart;
intstart = intend;
intend = k;
}
}
if (intinc > 0)
{
for (int k = intstart; k <= intend; k += intinc)
{
generators.add(Integer.toString(k));
}
}
else
{
for (int k = intstart; k >= intend; k += intinc)
{
generators.add(Integer.toString(k));
}
}
}
else
{
char charstart = matcher.group("charstart").charAt(0);
char charend = matcher.group("charend").charAt(0);
if (charstart < charend)
{
for (char c = charstart; c <= charend; c++)
{
generators.add(Character.toString(c));
}
}
else
{
for (char c = charstart; c >= charend; c--)
{
generators.add(Character.toString(c));
}
}
}
}
else if (part.charAt(0) == '{' && part.charAt(part.length() - 1) == '}')
{
// Split on commas
braces = 0;
escaped = false;
doubleQuoted = false;
singleQuoted = false;
start = 1;
for (int i = 1; i < part.length() - 1; i++)
{
char c = part.charAt(i);
if (doubleQuoted && escaped)
{
escaped = false;
}
else if (escaped)
{
escaped = false;
}
else if (singleQuoted)
{
if (c == '\'')
{
singleQuoted = false;
}
}
else if (doubleQuoted)
{
if (c == '\\')
{
escaped = true;
}
else if (c == '\"')
{
doubleQuoted = false;
}
}
else if (c == '\\')
{
escaped = true;
}
else if (c == '\'')
{
singleQuoted = true;
}
else if (c == '"')
{
doubleQuoted = true;
}
else
{
if (c == '}')
{
braces--;
}
else if (c == '{')
{
braces++;
}
else if (c == ',' && braces == 0)
{
generators.add(part.subSequence(start, i));
start = i + 1;
}
}
}
if (start < part.length() - 1)
{
generators.add(part.subSequence(start, part.length() - 1));
}
List<CharSequence> l = new ArrayList<>();
for (CharSequence cs : generators) {
Object o1 = expand(cs, false, false, false);
for (Object o2 : toCollection(o1)) {
l.add(String.valueOf(o2));
}
}
generators = l;
// If there's no splitting comma, expand with the braces
if (generators.size() < 2)
{
generators = Collections.<CharSequence>singletonList(part.toString());
}
}
else
{
generators.add(part.toString());
}
if (generated.isEmpty())
{
generated.addAll(generators);
}
else
{
List<CharSequence> prevGenerated = generated;
generated = new ArrayList<>();
for (CharSequence s : generators) {
for (Object cs : prevGenerated) {
generated.add(String.valueOf(cs) + s);
}
}
}
}
return generated;
}