1
2
3
4
5
6
7
8
9
10
11
12
13
14 package ch.qos.logback.core.pattern.parser;
15
16 import java.util.ArrayList;
17 import java.util.List;
18
19 import ch.qos.logback.core.pattern.util.AsIsEscapeUtil;
20 import ch.qos.logback.core.pattern.util.IEscapeUtil;
21
22 import static ch.qos.logback.core.CoreConstants.CURLY_RIGHT;
23
24 import static ch.qos.logback.core.CoreConstants.ESCAPE_CHAR;
25 import static ch.qos.logback.core.CoreConstants.COMMA_CHAR;
26 import static ch.qos.logback.core.CoreConstants.SINGLE_QUOTE_CHAR;
27 import static ch.qos.logback.core.CoreConstants.DOUBLE_QUOTE_CHAR;
28
29 import ch.qos.logback.core.pattern.parser.TokenStream.TokenizerState;
30 import ch.qos.logback.core.spi.ScanException;
31
32 public class OptionTokenizer {
33
34 private final static int EXPECTING_STATE = 0;
35 private final static int RAW_COLLECTING_STATE = 1;
36 private final static int QUOTED_COLLECTING_STATE = 2;
37
38 final IEscapeUtil escapeUtil;
39 final TokenStream tokenStream;
40 final String pattern;
41 final int patternLength;
42
43 char quoteChar;
44 int state = EXPECTING_STATE;
45
46 OptionTokenizer(TokenStream tokenStream) {
47 this(tokenStream, new AsIsEscapeUtil());
48 }
49
50 OptionTokenizer(TokenStream tokenStream, IEscapeUtil escapeUtil) {
51 this.tokenStream = tokenStream;
52 this.pattern = tokenStream.pattern;
53 this.patternLength = tokenStream.patternLength;
54 this.escapeUtil = escapeUtil;
55 }
56
57 void tokenize(char firstChar, List<Token> tokenList) throws ScanException {
58 StringBuffer buf = new StringBuffer();
59 List<String> optionList = new ArrayList<String>();
60 char c = firstChar;
61
62 while (tokenStream.pointer < patternLength) {
63 switch (state) {
64 case EXPECTING_STATE:
65 switch (c) {
66 case ' ':
67 case '\t':
68 case '\r':
69 case '\n':
70 case COMMA_CHAR:
71 break;
72 case SINGLE_QUOTE_CHAR:
73 case DOUBLE_QUOTE_CHAR:
74 state = QUOTED_COLLECTING_STATE;
75 quoteChar = c;
76 break;
77 case CURLY_RIGHT:
78 emitOptionToken(tokenList, optionList);
79 return;
80 default:
81 buf.append(c);
82 state = RAW_COLLECTING_STATE;
83 }
84 break;
85 case RAW_COLLECTING_STATE:
86 switch (c) {
87 case COMMA_CHAR:
88 optionList.add(buf.toString().trim());
89 buf.setLength(0);
90 state = EXPECTING_STATE;
91 break;
92 case CURLY_RIGHT:
93 optionList.add(buf.toString().trim());
94 emitOptionToken(tokenList, optionList);
95 return;
96 default:
97 buf.append(c);
98 }
99 break;
100 case QUOTED_COLLECTING_STATE:
101 if (c == quoteChar) {
102 optionList.add(buf.toString());
103 buf.setLength(0);
104 state = EXPECTING_STATE;
105 } else if (c == ESCAPE_CHAR) {
106 escape(String.valueOf(quoteChar), buf);
107 } else {
108 buf.append(c);
109 }
110
111 break;
112 }
113
114 c = pattern.charAt(tokenStream.pointer);
115 tokenStream.pointer++;
116 }
117
118
119 if (c == CURLY_RIGHT) {
120 if (state == EXPECTING_STATE) {
121 emitOptionToken(tokenList, optionList);
122 } else if (state == RAW_COLLECTING_STATE) {
123 optionList.add(buf.toString().trim());
124 emitOptionToken(tokenList, optionList);
125 } else {
126 throw new ScanException("Unexpected end of pattern string in OptionTokenizer");
127 }
128 } else {
129 throw new ScanException("Unexpected end of pattern string in OptionTokenizer");
130 }
131 }
132
133 void emitOptionToken(List<Token> tokenList, List<String> optionList) {
134 tokenList.add(new Token(Token.OPTION, optionList));
135 tokenStream.state = TokenizerState.LITERAL_STATE;
136 }
137
138 void escape(String escapeChars, StringBuffer buf) {
139 if ((tokenStream.pointer < patternLength)) {
140 char next = pattern.charAt(tokenStream.pointer++);
141 escapeUtil.escape(escapeChars, buf, next, tokenStream.pointer);
142 }
143 }
144 }