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