View Javadoc

1   package ch.qos.logback.core.pattern.parser;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import ch.qos.logback.core.pattern.util.IEscapeUtil;
7   import ch.qos.logback.core.pattern.util.RegularEscapeUtil;
8   
9   public class OptionTokenizer {
10  
11    private final static int EXPECTING_STATE = 0;
12    private final static int COLLECTING_STATE = 1;
13    private final static int QUOTED_COLLECTING_STATE = 2;
14  
15    private static final char ESCAPE_CHAR = '\\';
16    private static final char COMMA_CHAR = ',';
17    private static final char DOUBLE_QUOTE_CHAR = '"';
18    private static final char SINGLE_QUOTE_CHAR = '\'';
19  
20    final String pattern;
21    final int patternLength;
22    final IEscapeUtil escapeUtil;
23    
24    char quoteChar;
25    int pointer = 0;
26    int state = EXPECTING_STATE;
27  
28    /**
29     * This variant is used in tests
30     * @param pattern
31     */
32    OptionTokenizer(String pattern) {
33      this(pattern, new RegularEscapeUtil());
34    }
35    
36    OptionTokenizer(String pattern, IEscapeUtil escapeUtil) {
37      this.pattern = pattern;
38      patternLength = pattern.length();
39      this.escapeUtil = escapeUtil;
40    }
41  
42    List tokenize() throws ScanException {
43      List<String> tokenList = new ArrayList<String>();
44      StringBuffer buf = new StringBuffer();
45  
46      while (pointer < patternLength) {
47        char c = pattern.charAt(pointer);
48        pointer++;
49  
50        switch (state) {
51        case EXPECTING_STATE:
52          switch (c) {
53          case ' ':
54          case '\t':
55          case '\r':
56          case '\n':
57            break;
58          case SINGLE_QUOTE_CHAR:
59          case DOUBLE_QUOTE_CHAR:
60            state = QUOTED_COLLECTING_STATE;
61            quoteChar = c;
62            break;
63          default:
64            buf.append(c);
65            state = COLLECTING_STATE;
66          }
67          break;
68        case COLLECTING_STATE:
69          switch (c) {
70          case COMMA_CHAR:
71            tokenList.add(buf.toString().trim());
72            buf.setLength(0);
73            state = EXPECTING_STATE;
74            break;
75          default:
76            buf.append(c);
77          }
78          break;
79        case QUOTED_COLLECTING_STATE:
80          if (c == quoteChar) {
81            tokenList.add(buf.toString());
82            buf.setLength(0);
83            state = EXPECTING_STATE;
84          } else if (c == ESCAPE_CHAR) {
85            escape(String.valueOf(quoteChar), buf);
86          } else {
87            buf.append(c);
88          }
89  
90          break;
91        }
92      }
93  
94      // EOS
95      switch (state) {
96      case EXPECTING_STATE:
97        break;
98      case COLLECTING_STATE:
99        tokenList.add(buf.toString().trim());
100       break;
101     default:
102       throw new ScanException("Unexpected end of pattern string");
103     }
104 
105     return tokenList;
106   }
107 
108   void escape(String escapeChars, StringBuffer buf) {
109     if ((pointer < patternLength)) {
110       char next = pattern.charAt(pointer++);
111       escapeUtil.escape(escapeChars, buf, next, pointer);
112     }
113   }
114 }