1 /**
2  * Logback: the reliable, generic, fast and flexible logging framework.
3  * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4  *
5  * This program and the accompanying materials are dual-licensed under
6  * either the terms of the Eclipse Public License v1.0 as published by
7  * the Eclipse Foundation
8  *
9  *   or (per the licensee's choosing)
10  *
11  * under the terms of the GNU Lesser General Public License version 2.1
12  * as published by the Free Software Foundation.
13  */

14 package ch.qos.logback.core.subst;
15
16 import ch.qos.logback.core.CoreConstants;
17 import ch.qos.logback.core.spi.ScanException;
18
19 import java.util.ArrayList;
20 import java.util.List;
21
22 public class Tokenizer {
23
24     enum TokenizerState {
25         LITERAL_STATE, START_STATE, DEFAULT_VAL_STATE
26     }
27
28     final String pattern;
29     final int patternLength;
30
31     public Tokenizer(String pattern) {
32         this.pattern = pattern;
33         patternLength = pattern.length();
34     }
35
36     TokenizerState state = TokenizerState.LITERAL_STATE;
37     int pointer = 0;
38
39     List<Token> tokenize() throws ScanException {
40         List<Token> tokenList = new ArrayList<Token>();
41         StringBuilder buf = new StringBuilder();
42
43         while (pointer < patternLength) {
44             char c = pattern.charAt(pointer);
45             pointer++;
46
47             switch (state) {
48             case LITERAL_STATE:
49                 handleLiteralState(c, tokenList, buf);
50                 break;
51             case START_STATE:
52                 handleStartState(c, tokenList, buf);
53                 break;
54             case DEFAULT_VAL_STATE:
55                 handleDefaultValueState(c, tokenList, buf);
56             default:
57             }
58         }
59         // EOS
60         switch (state) {
61         case LITERAL_STATE:
62             addLiteralToken(tokenList, buf);
63             break;
64         case DEFAULT_VAL_STATE:
65             // trailing colon. see also LOGBACK-1140
66             buf.append(CoreConstants.COLON_CHAR);
67             addLiteralToken(tokenList, buf);
68             break;
69         case START_STATE:
70          // trailing $. see also LOGBACK-1149
71             buf.append(CoreConstants.DOLLAR);
72             addLiteralToken(tokenList, buf);
73             break;
74         }
75         return tokenList;
76     }
77
78     private void handleDefaultValueState(char c, List<Token> tokenList, StringBuilder stringBuilder) {
79         switch (c) {
80         case CoreConstants.DASH_CHAR:
81             tokenList.add(Token.DEFAULT_SEP_TOKEN);
82             state = TokenizerState.LITERAL_STATE;
83             break;
84         case CoreConstants.DOLLAR:
85             stringBuilder.append(CoreConstants.COLON_CHAR);
86             addLiteralToken(tokenList, stringBuilder);
87             stringBuilder.setLength(0);
88             state = TokenizerState.START_STATE;
89             break;
90         default:
91             stringBuilder.append(CoreConstants.COLON_CHAR).append(c);
92             state = TokenizerState.LITERAL_STATE;
93             break;
94         }
95     }
96
97     private void handleStartState(char c, List<Token> tokenList, StringBuilder stringBuilder) {
98         if (c == CoreConstants.CURLY_LEFT) {
99             tokenList.add(Token.START_TOKEN);
100         } else {
101             stringBuilder.append(CoreConstants.DOLLAR).append(c);
102         }
103         state = TokenizerState.LITERAL_STATE;
104     }
105
106     private void handleLiteralState(char c, List<Token> tokenList, StringBuilder stringBuilder) {
107         if (c == CoreConstants.DOLLAR) {
108             addLiteralToken(tokenList, stringBuilder);
109             stringBuilder.setLength(0);
110             state = TokenizerState.START_STATE;
111         } else if (c == CoreConstants.COLON_CHAR) {
112             addLiteralToken(tokenList, stringBuilder);
113             stringBuilder.setLength(0);
114             state = TokenizerState.DEFAULT_VAL_STATE;
115         } else if (c == CoreConstants.CURLY_LEFT) {
116             addLiteralToken(tokenList, stringBuilder);
117             tokenList.add(Token.CURLY_LEFT_TOKEN);
118             stringBuilder.setLength(0);
119         } else if (c == CoreConstants.CURLY_RIGHT) {
120             addLiteralToken(tokenList, stringBuilder);
121             tokenList.add(Token.CURLY_RIGHT_TOKEN);
122             stringBuilder.setLength(0);
123         } else {
124             stringBuilder.append(c);
125         }
126
127     }
128
129     private void addLiteralToken(List<Token> tokenList, StringBuilder stringBuilder) {
130         if (stringBuilder.length() == 0)
131             return;
132         tokenList.add(new Token(Token.Type.LITERAL, stringBuilder.toString()));
133     }
134
135 }
136