public static List getGlobsAfterBraceExpansion()

in brooklyn-server/utils/common/src/main/java/org/apache/brooklyn/util/text/WildcardGlobs.java [113:319]


    public static List<String> getGlobsAfterBraceExpansion(String pattern, boolean allowNumericRanges, PhraseTreatment quoteTreatment, PhraseTreatment parenthesesTreatment) throws InvalidPatternException {
        List<ExpressionToExpand> patterns = new ArrayList<ExpressionToExpand>();
        List<String> result = new ArrayList<String>();
        patterns.add(new ExpressionToExpand("", pattern, ""));
        while (!patterns.isEmpty()) {
            ExpressionToExpand cs = patterns.remove(0);
            StringBuffer resultSoFar = new StringBuffer(cs.resultSoFar);
            String operatorStack = cs.operatorStack;
            boolean inQuote = operatorStack.contains("\"");
            boolean expanded = false;
            for (int i=0; i<cs.todo.length(); i++) {
                assert !expanded;
                char c = cs.todo.charAt(i);
                boolean inParen = operatorStack.contains("(") &&
                    (!inQuote || operatorStack.lastIndexOf('\"')<operatorStack.lastIndexOf('('));
                if (inQuote && !(inParen && parenthesesTreatment.equals(PhraseTreatment.INTERIOR_NOT_EXPANDABLE))) {
                    if (c=='"') {
                        if (i>0 && cs.todo.charAt(i-1)=='\\') {
                            //this escaped quote, keep
                            resultSoFar.append(c);
                            continue;
                        }
                        //unquote
                        resultSoFar.append(c);
                        inQuote = false;
                        if (operatorStack.charAt(operatorStack.length()-1)!='\"')
                            throw new InvalidPatternException("Quoted string contents not valid, after parsing "+resultSoFar);
                        operatorStack = operatorStack.substring(0, operatorStack.length()-1);
                        continue;
                    }
                    if (quoteTreatment.equals(PhraseTreatment.INTERIOR_NOT_EXPANDABLE)) {
                        resultSoFar.append(c);
                        continue;
                    }
                    //interior is expandable, continue parsing as usual below
                }
                if (inParen) {
                    if (c==')') {
                        //unparen
                        resultSoFar.append(c);
                        if (operatorStack.charAt(operatorStack.length()-1)!='(')
                            throw new InvalidPatternException("Parenthetical contents not valid, after parsing "+resultSoFar);
                        operatorStack = operatorStack.substring(0, operatorStack.length()-1);
                        continue;
                    }
                    if (parenthesesTreatment.equals(PhraseTreatment.INTERIOR_NOT_EXPANDABLE)) {
                        resultSoFar.append(c);
                        if (c=='(')
                            operatorStack+="(";
                        continue;
                    }
                    //interior is expandable, continue parsing as usual below
                }

                if (c=='"' && !quoteTreatment.equals(PhraseTreatment.NOT_A_SPECIAL_CHAR)) {
                    resultSoFar.append(c);
                    inQuote = true;
                    operatorStack += "\"";
                    continue;
                }
                if (c=='(' && !parenthesesTreatment.equals(PhraseTreatment.NOT_A_SPECIAL_CHAR)) {
                    resultSoFar.append(c);
                    operatorStack += "(";
                    continue;
                }

                if (c!='{') {
                    resultSoFar.append(c);
                    continue;
                }

                //brace.. we will need to expand
                expanded = true;
                String operatorStackBeforeExpansion = operatorStack;
                int braceStartIndex = i;
                int tokenStartIndex = i+1;

                //find matching close brace
                List<String> tokens = new ArrayList<String>();
                operatorStack += "{";
                while (true) {
                    if (++i>=cs.todo.length()) {
                        throw new InvalidPatternException("Curly brace not closed, parsing '"+cs.todo.substring(braceStartIndex)+"' after "+resultSoFar);
                    }
                    c = cs.todo.charAt(i);
                    inParen = operatorStack.contains("(") &&
                        (!inQuote || operatorStack.lastIndexOf('\"')<operatorStack.lastIndexOf('('));
                    if (inQuote && !(inParen && parenthesesTreatment.equals(PhraseTreatment.INTERIOR_NOT_EXPANDABLE))) {
                        if (c=='"') {
                            if (i>0 && cs.todo.charAt(i-1)=='\\') {
                                //this is escaped quote, doesn't affect status
                                continue;
                            }
                            //unquote
                            inQuote = false;
                            if (operatorStack.charAt(operatorStack.length()-1)!='\"')
                                throw new InvalidPatternException("Quoted string contents not valid, after parsing "+resultSoFar+cs.todo.substring(braceStartIndex, i));
                            operatorStack = operatorStack.substring(0, operatorStack.length()-1);
                            continue;
                        }
                        if (quoteTreatment.equals(PhraseTreatment.INTERIOR_NOT_EXPANDABLE)) {
                            continue;
                        }
                        //interior is expandable, continue parsing as usual below
                    }
                    if (inParen) {
                        if (c==')') {
                            //unparen
                            if (operatorStack.charAt(operatorStack.length()-1)!='(')
                                throw new InvalidPatternException("Parenthetical contents not valid, after parsing "+resultSoFar+cs.todo.substring(braceStartIndex, i));
                            operatorStack = operatorStack.substring(0, operatorStack.length()-1);
                            continue;
                        }
                        if (parenthesesTreatment.equals(PhraseTreatment.INTERIOR_NOT_EXPANDABLE)) {
                            if (c=='(')
                                operatorStack+="(";
                            continue;
                        }
                        //interior is expandable, continue parsing as usual below
                    }

                    if (c=='"' && !quoteTreatment.equals(PhraseTreatment.NOT_A_SPECIAL_CHAR)) {
                        inQuote = true;
                        operatorStack += "\"";
                        continue;
                    }
                    if (c=='(' && !parenthesesTreatment.equals(PhraseTreatment.NOT_A_SPECIAL_CHAR)) {
                        operatorStack += "(";
                        continue;
                    }

                    if (c=='}') {
                        if (operatorStack.charAt(operatorStack.length()-1)!='{')
                            throw new InvalidPatternException("Brace contents not valid, mismatched operators "+operatorStack+" after parsing "+resultSoFar+cs.todo.substring(braceStartIndex, i));
                        operatorStack = operatorStack.substring(0, operatorStack.length()-1);
                        if (operatorStack.equals(operatorStackBeforeExpansion)) {
                            tokens.add(cs.todo.substring(tokenStartIndex, i));
                            break;
                        }
                        continue;
                    }

                    if (c==',') {
                        if (operatorStack.length()==operatorStackBeforeExpansion.length()+1) {
                            tokens.add(cs.todo.substring(tokenStartIndex, i));
                            tokenStartIndex = i+1;
                            continue;
                        }
                        continue;
                    }

                    if (c=='{') {
                        operatorStack += c;
                        continue;
                    }

                    //any other char is irrelevant
                    continue;
                }

                assert operatorStack.equals(operatorStackBeforeExpansion);
                assert cs.todo.charAt(i)=='}';
                assert !tokens.isEmpty();

                String suffix = cs.todo.substring(i+1);

                List<ExpressionToExpand> newPatterns = new ArrayList<ExpressionToExpand>();
                for (String token : tokens) {
                    //System.out.println("adding: "+pre+token+post);
                    if (allowNumericRanges && token.matches("\\s*[0-9]+\\s*-\\s*[0-9]+\\s*")) {
                        int dashIndex = token.indexOf('-');
                        String startS = token.substring(0, dashIndex).trim();
                        String endS = token.substring(dashIndex+1).trim();

                        int start = Integer.parseInt(startS);
                        int end = Integer.parseInt(endS);

                        if (startS.startsWith("-")) startS=startS.substring(1).trim();
                        if (endS.startsWith("-")) endS=endS.substring(1).trim();
                        int minLen = Math.min(startS.length(), endS.length());

                        for (int ti=start; ti<=end; ti++) {
                            //partial support for negative numbers, but of course they cannot (yet) be specified in the regex above so it is moot
                            String tokenI = ""+Math.abs(ti);
                            while (tokenI.length()<minLen) tokenI = "0"+tokenI;
                            if (ti<0) tokenI = "-"+tokenI;
                            newPatterns.add(new ExpressionToExpand(resultSoFar.toString(), tokenI+suffix, operatorStackBeforeExpansion));                              
                        }
                    } else {
                        newPatterns.add(new ExpressionToExpand(resultSoFar.toString(), token+suffix, operatorStackBeforeExpansion));
                    }
                }
                // insert new patterns at the start, so we continue to expand them next
                patterns.addAll(0, newPatterns);
                
                break;
            }
            if (!expanded) {
                if (operatorStack.length()>0) {
                    throw new InvalidPatternException("Unclosed operators "+operatorStack+" parsing "+resultSoFar);
                }
                result.add(resultSoFar.toString());
            }
        }
        assert !result.isEmpty();
        return result;
    }