private int substitute(final StrBuilder buf,final int offset,final int length,List<String> priorVariables){
  final StrMatcher pfxMatcher=getVariablePrefixMatcher();
  final StrMatcher suffMatcher=getVariableSuffixMatcher();
  final char escape=getEscapeChar();
  final StrMatcher valueDelimMatcher=getValueDelimiterMatcher();
  final boolean substitutionInVariablesEnabled=isEnableSubstitutionInVariables();
  final boolean top=priorVariables == null;
  boolean altered=false;
  int lengthChange=0;
  char[] chars=buf.buffer;
  int bufEnd=offset + length;
  int pos=offset;
  while (pos < bufEnd) {
    final int startMatchLen=pfxMatcher.isMatch(chars,pos,offset,bufEnd);
    if (startMatchLen == 0) {
      pos++;
    }
 else {
      if (pos > offset && chars[pos - 1] == escape) {
        buf.deleteCharAt(pos - 1);
        chars=buf.buffer;
        lengthChange--;
        altered=true;
        bufEnd--;
      }
 else {
        final int startPos=pos;
        pos+=startMatchLen;
        int endMatchLen=0;
        int nestedVarCount=0;
        while (pos < bufEnd) {
          if (substitutionInVariablesEnabled && (endMatchLen=pfxMatcher.isMatch(chars,pos,offset,bufEnd)) != 0) {
            nestedVarCount++;
            pos+=endMatchLen;
            continue;
          }
          endMatchLen=suffMatcher.isMatch(chars,pos,offset,bufEnd);
          if (endMatchLen == 0) {
            pos++;
          }
 else {
            if (nestedVarCount == 0) {
              String varNameExpr=new String(chars,startPos + startMatchLen,pos - startPos - startMatchLen);
              if (substitutionInVariablesEnabled) {
                final StrBuilder bufName=new StrBuilder(varNameExpr);
                substitute(bufName,0,bufName.length());
                varNameExpr=bufName.toString();
              }
              pos+=endMatchLen;
              final int endPos=pos;
              String varName=varNameExpr;
              String varDefaultValue=null;
              if (valueDelimMatcher != null) {
                final char[] varNameExprChars=varNameExpr.toCharArray();
                int valueDelimiterMatchLen=0;
                for (int i=0; i < varNameExprChars.length; i++) {
                  if (!substitutionInVariablesEnabled && pfxMatcher.isMatch(varNameExprChars,i,i,varNameExprChars.length) != 0) {
                    break;
                  }
                  if ((valueDelimiterMatchLen=valueDelimMatcher.isMatch(varNameExprChars,i)) != 0) {
                    varName=varNameExpr.substring(0,i);
                    varDefaultValue=varNameExpr.substring(i + valueDelimiterMatchLen);
                    break;
                  }
                }
              }
              if (priorVariables == null) {
                priorVariables=new ArrayList<String>();
                priorVariables.add(new String(chars,offset,length));
              }
              checkCyclicSubstitution(varName,priorVariables);
              priorVariables.add(varName);
              String varValue=resolveVariable(varName,buf,startPos,endPos);
              if (varValue == null) {
                varValue=varDefaultValue;
              }
              if (varValue != null) {
                final int varLen=varValue.length();
                buf.replace(startPos,endPos,varValue);
                altered=true;
                int change=substitute(buf,startPos,varLen,priorVariables);
                change=change + varLen - (endPos - startPos);
                pos+=change;
                bufEnd+=change;
                lengthChange+=change;
                chars=buf.buffer;
              }
              priorVariables.remove(priorVariables.size() - 1);
              break;
            }
            nestedVarCount--;
            pos+=endMatchLen;
          }
        }
      }
    }
  }
  if (top) {
    return altered ? 1 : 0;
  }
  return lengthChange;
}

private int substitute ( final StrBuilder buf , final int offset , final int length , List < String > priorVariables ) { final StrMatcher pfxMatcher = getVariablePrefixMatcher ( ) ; final StrMatcher suffMatcher = getVariableSuffixMatcher ( ) ; final char escape = getEscapeChar ( ) ; final StrMatcher valueDelimMatcher = getValueDelimiterMatcher ( ) ; final boolean substitutionInVariablesEnabled = isEnableSubstitutionInVariables ( ) ; final boolean top = priorVariables == null ; boolean altered = false ; int lengthChange = 0 ; char [ ] chars = buf . buffer ; int bufEnd = offset + length ; int pos = offset ; while ( pos < bufEnd ) { final int startMatchLen = pfxMatcher . isMatch ( chars , pos , offset , bufEnd ) ; if ( startMatchLen == 0 ) { pos ++ ; } else { if ( pos > offset && chars [ pos - 1 ] == escape ) { buf . deleteCharAt ( pos - 1 ) ; chars = buf . buffer ; lengthChange -- ; altered = true ; bufEnd -- ; } else { final int startPos = pos ; pos += startMatchLen ; int endMatchLen = 0 ; int nestedVarCount = 0 ; while ( pos < bufEnd ) { if ( substitutionInVariablesEnabled && ( endMatchLen = pfxMatcher . isMatch ( chars , pos , offset , bufEnd ) ) != 0 ) { nestedVarCount ++ ; pos += endMatchLen ; continue ; } endMatchLen = suffMatcher . isMatch ( chars , pos , offset , bufEnd ) ; if ( endMatchLen == 0 ) { pos ++ ; } else { if ( nestedVarCount == 0 ) { String varNameExpr = new String ( chars , startPos + startMatchLen , pos - startPos - startMatchLen ) ; if ( substitutionInVariablesEnabled ) { final StrBuilder bufName = new StrBuilder ( varNameExpr ) ; substitute ( bufName , 0 , bufName . length ( ) ) ; varNameExpr = bufName . toString ( ) ; } pos += endMatchLen ; final int endPos = pos ; String varName = varNameExpr ; String varDefaultValue = null ; if ( valueDelimMatcher != null ) { final char [ ] varNameExprChars = varNameExpr . toCharArray ( ) ; int valueDelimiterMatchLen = 0 ; for ( int i = 0 ; i < varNameExprChars . length ; i ++ ) { if ( ! substitutionInVariablesEnabled && pfxMatcher . isMatch ( varNameExprChars , i , i , varNameExprChars . length ) != 0 ) { break ; } if ( ( valueDelimiterMatchLen = valueDelimMatcher . isMatch ( varNameExprChars , i ) ) != 0 ) { varName = varNameExpr . substring ( 0 , i ) ; varDefaultValue = varNameExpr . substring ( i + valueDelimiterMatchLen ) ; break ; } } } if ( priorVariables == null ) { priorVariables = new ArrayList < String > ( ) ; priorVariables . add ( new String ( chars , offset , length ) ) ; } checkCyclicSubstitution ( varName , priorVariables ) ; priorVariables . add ( varName ) ; String varValue = resolveVariable ( varName , buf , startPos , endPos ) ; if ( varValue == null ) { varValue = varDefaultValue ; } if ( varValue != null ) { final int varLen = varValue . length ( ) ; buf . replace ( startPos , endPos , varValue ) ; altered = true ; int change = substitute ( buf , startPos , varLen , priorVariables ) ; change = change + varLen - ( endPos - startPos ) ; pos += change ; bufEnd += change ; lengthChange += change ; chars = buf . buffer ; } priorVariables . remove ( priorVariables . size ( ) - 1 ) ; break ; } nestedVarCount -- ; pos += endMatchLen ; } } } } } if ( top ) { return altered ? 1 : 0 ; } return lengthChange ; }
recursive handler for multiple levels of interpolation . this is the main interpolation method , which resolves the values of all variable references contained in the passed in text .
