1
2
3
4
5
6
7
8
9
10 package ch.qos.logback.core.pattern.parser;
11
12 import java.util.List;
13 import java.util.ArrayList;
14
15 import ch.qos.logback.core.CoreConstants;
16 import ch.qos.logback.core.pattern.util.IEscapeUtil;
17 import ch.qos.logback.core.pattern.util.RegularEscapeUtil;
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 class TokenStream {
34
35 private static final char ESCAPE_CHAR = '\\';
36 private static final char PERCENT_CHAR = CoreConstants.PERCENT_CHAR;
37 private static final char LEFT_PARENTHESIS = '(';
38 private static final char RIGHT_PARENTHESIS = ')';
39 private static final char CURLY_LEFT = '{';
40 private static final char CURLY_RIGHT = '}';
41
42 private static final int LITERAL_STATE = 0;
43 private static final int FORMAT_MODIFIER_STATE = 1;
44 private static final int KEYWORD_STATE = 2;
45 private static final int OPTION_STATE = 3;
46
47 final String pattern;
48 final int patternLength;
49 final IEscapeUtil escapeUtil;
50
51 int state = LITERAL_STATE;
52 int pointer = 0;
53
54
55 TokenStream(String pattern) {
56 this(pattern, new RegularEscapeUtil());
57 }
58
59 TokenStream(String pattern, IEscapeUtil escapeUtil) {
60 if(pattern == null) {
61 throw new NullPointerException("null pattern string not allowed");
62 }
63 this.pattern = pattern;
64 patternLength = pattern.length();
65 this.escapeUtil = escapeUtil;
66 }
67
68 List tokenize() throws ScanException {
69 List<Token> tokenList = new ArrayList<Token>();
70 StringBuffer buf = new StringBuffer();
71
72 while (pointer < patternLength) {
73 char c = pattern.charAt(pointer);
74 pointer++;
75
76 switch (state) {
77
78 case LITERAL_STATE:
79 switch (c) {
80 case ESCAPE_CHAR:
81 escape("%()", buf);
82 break;
83 case PERCENT_CHAR:
84 addValuedToken(Token.LITERAL, buf, tokenList);
85 tokenList.add(Token.PERCENT_TOKEN);
86 state = FORMAT_MODIFIER_STATE;
87 break;
88
89 case RIGHT_PARENTHESIS:
90 if (buf.length() >= 1 && buf.charAt(buf.length() - 1) == '\\') {
91 buf.deleteCharAt(buf.length() - 1);
92 buf.append(RIGHT_PARENTHESIS);
93 } else {
94 addValuedToken(Token.LITERAL, buf, tokenList);
95 tokenList.add(Token.RIGHT_PARENTHESIS_TOKEN);
96 }
97 break;
98
99 default:
100 buf.append(c);
101 }
102 break;
103
104 case FORMAT_MODIFIER_STATE:
105 if (c == LEFT_PARENTHESIS) {
106 addValuedToken(Token.FORMAT_MODIFIER, buf, tokenList);
107 tokenList.add(Token.LEFT_PARENTHESIS_TOKEN);
108 state = LITERAL_STATE;
109 } else if (Character.isJavaIdentifierStart(c)) {
110 addValuedToken(Token.FORMAT_MODIFIER, buf, tokenList);
111 state = KEYWORD_STATE;
112 buf.append(c);
113 } else {
114 buf.append(c);
115 }
116 break;
117 case OPTION_STATE:
118 switch (c) {
119 case CURLY_RIGHT:
120 addValuedToken(Token.OPTION, buf, tokenList);
121 state = LITERAL_STATE;
122 break;
123 case ESCAPE_CHAR:
124 escape("%{}", buf);
125 break;
126 default:
127 buf.append(c);
128 }
129 break;
130 case KEYWORD_STATE:
131 if (c == CURLY_LEFT) {
132 addValuedToken(Token.KEYWORD, buf, tokenList);
133 state = OPTION_STATE;
134 } else if (Character.isJavaIdentifierPart(c)) {
135 buf.append(c);
136 } else if (c == PERCENT_CHAR) {
137 addValuedToken(Token.KEYWORD, buf, tokenList);
138 tokenList.add(Token.PERCENT_TOKEN);
139 state = FORMAT_MODIFIER_STATE;
140 } else {
141 addValuedToken(Token.KEYWORD, buf, tokenList);
142 if (c == RIGHT_PARENTHESIS) {
143
144 tokenList.add(Token.RIGHT_PARENTHESIS_TOKEN);
145 } else if (c == ESCAPE_CHAR) {
146 if ((pointer < patternLength)) {
147 char next = pattern.charAt(pointer++);
148 escapeUtil.escape("%()", buf, next, pointer);
149 }
150 } else {
151 buf.append(c);
152 }
153 state = LITERAL_STATE;
154 }
155 break;
156
157 default:
158 }
159 }
160
161
162 switch (state) {
163 case LITERAL_STATE:
164 addValuedToken(Token.LITERAL, buf, tokenList);
165 break;
166 case KEYWORD_STATE:
167 tokenList.add(new Token(Token.KEYWORD, buf.toString()));
168 buf.setLength(0);
169 break;
170
171 case FORMAT_MODIFIER_STATE:
172 case OPTION_STATE:
173 throw new ScanException("Unexpected end of pattern string");
174 }
175
176 return tokenList;
177 }
178
179 void escape(String escapeChars, StringBuffer buf) {
180 if ((pointer < patternLength)) {
181 char next = pattern.charAt(pointer++);
182 escapeUtil.escape(escapeChars, buf, next, pointer);
183 }
184 }
185
186 private void addValuedToken(int type, StringBuffer buf, List<Token> tokenList) {
187 if (buf.length() > 0) {
188 tokenList.add(new Token(type, buf.toString()));
189 buf.setLength(0);
190 }
191 }
192 }