View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2011, 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.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     // EOS
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 }