/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include using namespace log4cxx; using namespace log4cxx::pattern; using namespace log4cxx::helpers; const logchar PatternParser::ESCAPE_CHAR = 0x25; // '%' /** * Private constructor. */ PatternParser::PatternParser() { } bool PatternParser::isUnicodeIdentifierStart(logchar ch) { // // greatly simplified version checks if // character is USACII alpha or number // return (ch >= 0x41 /* 'A' */ && ch <= 0x5A /* 'Z' */) || (ch >= 0x61 /* 'a' */ && ch <= 0x7A /* 'z' */) || (ch >= 0x30 /* '0' */ && ch <= 0x39 /* '9' */); } bool PatternParser::isUnicodeIdentifierPart(logchar ch) { // // greatly simplified version checks if // character is USACII alpha or number // return isUnicodeIdentifierStart(ch) || (ch == 0x5F /* '_' */); } int PatternParser::extractConverter( logchar lastChar, const LogString& pattern, LogString::size_type i, LogString& convBuf, LogString& currentLiteral) { if (!convBuf.empty()) { convBuf.erase(convBuf.begin(), convBuf.end()); } // When this method is called, lastChar points to the first character of the // conversion word. For example: // For "%hello" lastChar = 'h' // For "%-5hello" lastChar = 'h' //System.out.println("lastchar is "+lastChar); if (!isUnicodeIdentifierStart(lastChar)) { return i; } convBuf.append(1, lastChar); while ( (i < pattern.length()) && isUnicodeIdentifierPart(pattern[i])) { convBuf.append(1, pattern[i]); currentLiteral.append(1, pattern[i]); //System.out.println("conv buffer is now ["+convBuf+"]."); i++; } return i; } int PatternParser::extractOptions(const LogString& pattern, LogString::size_type i, std::vector& options) { while ((i < pattern.length()) && (pattern[i] == 0x7B /* '{' */)) { int end = pattern.find(0x7D /* '}' */, i); if (end == -1) { break; } LogString r(pattern.substr(i + 1, end - i - 1)); options.push_back(r); i = end + 1; } return i; } void PatternParser::parse( const LogString& pattern, std::vector& patternConverters, std::vector& formattingInfos, const PatternMap& rules) { LogString currentLiteral; int patternLength = pattern.length(); int state = LITERAL_STATE; logchar c; int i = 0; FormattingInfoPtr formattingInfo(FormattingInfo::getDefault()); while (i < patternLength) { c = pattern[i++]; switch (state) { case LITERAL_STATE: // In literal state, the last char is always a literal. if (i == patternLength) { currentLiteral.append(1, c); continue; } if (c == ESCAPE_CHAR) { // peek at the next char. if(pattern[i] == ESCAPE_CHAR) { currentLiteral.append(1, c); i++; // move pointer } else { if (!currentLiteral.empty()) { patternConverters.push_back( LiteralPatternConverter::newInstance(currentLiteral)); formattingInfos.push_back(FormattingInfo::getDefault()); currentLiteral.erase(currentLiteral.begin(), currentLiteral.end()); } currentLiteral.append(1, c); // append % state = CONVERTER_STATE; formattingInfo = FormattingInfo::getDefault(); } } else { currentLiteral.append(1, c); } break; case CONVERTER_STATE: currentLiteral.append(1, c); switch (c) { case 0x2D: // '-' formattingInfo = new FormattingInfo( true, formattingInfo->getMinLength(), formattingInfo->getMaxLength()); break; case 0x2E: // '.' state = DOT_STATE; break; default: if ((c >= 0x30 /* '0' */) && (c <= 0x39 /* '9' */)) { formattingInfo = new FormattingInfo( formattingInfo->isLeftAligned(), c - 0x30 /* '0' */, formattingInfo->getMaxLength()); state = MIN_STATE; } else { i = finalizeConverter( c, pattern, i, currentLiteral, formattingInfo, rules, patternConverters, formattingInfos); // Next pattern is assumed to be a literal. state = LITERAL_STATE; formattingInfo = FormattingInfo::getDefault(); if (!currentLiteral.empty()) { currentLiteral.erase(currentLiteral.begin(), currentLiteral.end()); } } } // switch break; case MIN_STATE: currentLiteral.append(1, c); if ((c >= 0x30 /* '0' */) && (c <= 0x39 /* '9' */)) { formattingInfo = new FormattingInfo( formattingInfo->isLeftAligned(), (formattingInfo->getMinLength() * 10) + (c - 0x30 /* '0' */), formattingInfo->getMaxLength()); } else if (c == 0x2E /* '.' */) { state = DOT_STATE; } else { i = finalizeConverter( c, pattern, i, currentLiteral, formattingInfo, rules, patternConverters, formattingInfos); state = LITERAL_STATE; formattingInfo = FormattingInfo::getDefault(); if (!currentLiteral.empty()) { currentLiteral.erase(currentLiteral.begin(), currentLiteral.end()); } } break; case DOT_STATE: currentLiteral.append(1, c); if ((c >= 0x30 /* '0' */) && (c <= 0x39 /* '9' */)) { formattingInfo = new FormattingInfo( formattingInfo->isLeftAligned(), formattingInfo->getMinLength(), c - 0x30 /* '0' */); state = MAX_STATE; } else { LogLog::error(LOG4CXX_STR("Error in pattern, was expecting digit.")); state = LITERAL_STATE; } break; case MAX_STATE: currentLiteral.append(1, c); if ((c >= 0x30 /* '0' */) && (c <= 0x39 /* '9' */)) { formattingInfo = new FormattingInfo( formattingInfo->isLeftAligned(), formattingInfo->getMinLength(), (formattingInfo->getMaxLength() * 10) + (c - 0x30 /* '0' */)); } else { i = finalizeConverter( c, pattern, i, currentLiteral, formattingInfo, rules, patternConverters, formattingInfos); state = LITERAL_STATE; formattingInfo = FormattingInfo::getDefault(); if (!currentLiteral.empty()) { currentLiteral.erase(currentLiteral.begin(), currentLiteral.end()); } } break; } // switch } // while if (currentLiteral.length() != 0) { patternConverters.push_back( LiteralPatternConverter::newInstance(currentLiteral)); formattingInfos.push_back(FormattingInfo::getDefault()); } } PatternConverterPtr PatternParser::createConverter( const LogString& converterId, LogString& currentLiteral, const PatternMap& rules, std::vector& options) { LogString converterName(converterId); for (int i = converterId.length(); i > 0; i--) { converterName = converterName.substr(0, i); PatternMap::const_iterator iter = rules.find(converterName); if (iter != rules.end()) { currentLiteral.erase(currentLiteral.begin(), currentLiteral.end() - (converterId.length() - i)); return (iter->second)(options); } } LogLog::error(LogString(LOG4CXX_STR("Unrecognized format specifier ")) + converterId); ObjectPtr converterObj; return converterObj; } int PatternParser::finalizeConverter( logchar c, const LogString& pattern, int i, LogString& currentLiteral, const FormattingInfoPtr& formattingInfo, const PatternMap& rules, std::vector& patternConverters, std::vector& formattingInfos) { LogString convBuf; i = extractConverter(c, pattern, i, convBuf, currentLiteral); if (convBuf.empty()) { LogLog::error(LOG4CXX_STR("Empty conversion specifier")); patternConverters.push_back( LiteralPatternConverter::newInstance(currentLiteral)); formattingInfos.push_back(FormattingInfo::getDefault()); } else { LogString converterId(convBuf); std::vector options; i = extractOptions(pattern, i, options); PatternConverterPtr pc( createConverter( converterId, currentLiteral, rules, options)); if (pc == NULL) { LogString msg(LOG4CXX_STR("Unrecognized conversion specifier [")); msg.append(converterId); msg.append(LOG4CXX_STR("] in conversion pattern.")); LogLog::error(msg); patternConverters.push_back( LiteralPatternConverter::newInstance(currentLiteral)); formattingInfos.push_back(FormattingInfo::getDefault()); } else { patternConverters.push_back(pc); formattingInfos.push_back(formattingInfo); if (currentLiteral.length() > 0) { patternConverters.push_back( LiteralPatternConverter::newInstance(currentLiteral)); formattingInfos.push_back(FormattingInfo::getDefault()); } } } if (!currentLiteral.empty()) { currentLiteral.erase(currentLiteral.begin(), currentLiteral.end()); } return i; }