/src/logging-log4cxx/src/main/cpp/patternparser.cpp
| Line | Count | Source | 
| 1 |  | /* | 
| 2 |  |  * Licensed to the Apache Software Foundation (ASF) under one or more | 
| 3 |  |  * contributor license agreements.  See the NOTICE file distributed with | 
| 4 |  |  * this work for additional information regarding copyright ownership. | 
| 5 |  |  * The ASF licenses this file to You under the Apache License, Version 2.0 | 
| 6 |  |  * (the "License"); you may not use this file except in compliance with | 
| 7 |  |  * the License.  You may obtain a copy of the License at | 
| 8 |  |  * | 
| 9 |  |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
| 10 |  |  * | 
| 11 |  |  * Unless required by applicable law or agreed to in writing, software | 
| 12 |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
| 13 |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
| 14 |  |  * See the License for the specific language governing permissions and | 
| 15 |  |  * limitations under the License. | 
| 16 |  |  */ | 
| 17 |  |  | 
| 18 |  | #include <log4cxx/logstring.h> | 
| 19 |  | #include <log4cxx/pattern/patternparser.h> | 
| 20 |  | #include <log4cxx/pattern/literalpatternconverter.h> | 
| 21 |  | #include <log4cxx/helpers/loglog.h> | 
| 22 |  |  | 
| 23 |  | using namespace LOG4CXX_NS; | 
| 24 |  | using namespace LOG4CXX_NS::pattern; | 
| 25 |  | using namespace LOG4CXX_NS::helpers; | 
| 26 |  |  | 
| 27 |  | const logchar PatternParser::ESCAPE_CHAR = 0x25; // '%' | 
| 28 |  |  | 
| 29 |  |  | 
| 30 |  | /** | 
| 31 |  |  * Private constructor. | 
| 32 |  |  */ | 
| 33 |  | PatternParser::PatternParser() | 
| 34 | 0 | { | 
| 35 | 0 | } | 
| 36 |  |  | 
| 37 |  | bool PatternParser::isUnicodeIdentifierStart(logchar ch) | 
| 38 | 492k | { | 
| 39 |  |   // | 
| 40 |  |   //   greatly simplified version checks if | 
| 41 |  |   //     character is USACII alpha or number | 
| 42 |  |   // | 
| 43 | 492k |   return (ch >= 0x41 /* 'A' */ && ch <= 0x5A /* 'Z' */) || | 
| 44 | 392k |     (ch >= 0x61 /* 'a' */ && ch <= 0x7A /* 'z' */) || | 
| 45 | 152k |     (ch >= 0x30 /* '0' */ && ch <= 0x39 /* '9' */); | 
| 46 | 492k | } | 
| 47 |  |  | 
| 48 |  | bool PatternParser::isUnicodeIdentifierPart(logchar ch) | 
| 49 | 367k | { | 
| 50 |  |   // | 
| 51 |  |   //   greatly simplified version checks if | 
| 52 |  |   //     character is USACII alpha or number | 
| 53 |  |   // | 
| 54 | 367k |   return isUnicodeIdentifierStart(ch) | 
| 55 | 119k |     || (ch == 0x5F /* '_' */); | 
| 56 | 367k | } | 
| 57 |  |  | 
| 58 |  | size_t PatternParser::extractConverter( | 
| 59 |  |   logchar lastChar, const LogString& pattern, | 
| 60 |  |   LogString::size_type i, LogString& convBuf, | 
| 61 |  |   LogString& currentLiteral) | 
| 62 | 125k | { | 
| 63 | 125k |   if (!convBuf.empty()) | 
| 64 | 0 |   { | 
| 65 | 0 |     convBuf.erase(convBuf.begin(), convBuf.end()); | 
| 66 | 0 |   } | 
| 67 |  |  | 
| 68 |  |   // When this method is called, lastChar points to the first character of the | 
| 69 |  |   // conversion word. For example: | 
| 70 |  |   // For "%hello"     lastChar = 'h' | 
| 71 |  |   // For "%-5hello"   lastChar = 'h' | 
| 72 |  |   //System.out.println("lastchar is "+lastChar); | 
| 73 | 125k |   if (!isUnicodeIdentifierStart(lastChar)) | 
| 74 | 5.98k |   { | 
| 75 | 5.98k |     return i; | 
| 76 | 5.98k |   } | 
| 77 |  |  | 
| 78 | 119k |   convBuf.append(1, lastChar); | 
| 79 |  |  | 
| 80 | 119k |   while ( | 
| 81 | 368k |     (i < pattern.length()) | 
| 82 | 367k |     && isUnicodeIdentifierPart(pattern[i])) | 
| 83 | 248k |   { | 
| 84 | 248k |     convBuf.append(1, pattern[i]); | 
| 85 | 248k |     currentLiteral.append(1, pattern[i]); | 
| 86 |  |  | 
| 87 |  |     //System.out.println("conv buffer is now ["+convBuf+"]."); | 
| 88 | 248k |     i++; | 
| 89 | 248k |   } | 
| 90 |  |  | 
| 91 | 119k |   return i; | 
| 92 | 125k | } | 
| 93 |  |  | 
| 94 |  |  | 
| 95 |  | size_t PatternParser::extractOptions(const LogString& pattern, LogString::size_type i, | 
| 96 |  |   std::vector<LogString>& options) | 
| 97 | 119k | { | 
| 98 | 181k |   while ((i < pattern.length()) && (pattern[i] == 0x7B /* '{' */)) | 
| 99 | 62.0k |   { | 
| 100 | 62.0k |     size_t end = pattern.find(0x7D /* '}' */, i); | 
| 101 |  |  | 
| 102 | 62.0k |     if (end == pattern.npos) | 
| 103 | 464 |     { | 
| 104 | 464 |       break; | 
| 105 | 464 |     } | 
| 106 |  |  | 
| 107 | 61.5k |     LogString r(pattern.substr(i + 1, end - i - 1)); | 
| 108 | 61.5k |     options.push_back(r); | 
| 109 | 61.5k |     i = end + 1; | 
| 110 | 61.5k |   } | 
| 111 |  |  | 
| 112 | 119k |   return i; | 
| 113 | 119k | } | 
| 114 |  |  | 
| 115 |  | void PatternParser::parse( | 
| 116 |  |   const LogString& pattern, | 
| 117 |  |   std::vector<PatternConverterPtr>& patternConverters, | 
| 118 |  |   std::vector<FormattingInfoPtr>& formattingInfos, | 
| 119 |  |   const PatternMap& rules) | 
| 120 | 3.76k | { | 
| 121 |  |  | 
| 122 | 3.76k |   LogString currentLiteral; | 
| 123 |  |  | 
| 124 | 3.76k |   size_t patternLength = pattern.length(); | 
| 125 | 3.76k |   int state = LITERAL_STATE; | 
| 126 | 3.76k |   logchar c; | 
| 127 | 3.76k |   size_t i = 0; | 
| 128 | 3.76k |   int minDigitCount{ 0 }, maxDigitCount{ 0 }; | 
| 129 | 3.76k |   FormattingInfoPtr formattingInfo(FormattingInfo::getDefault()); | 
| 130 |  |  | 
| 131 | 813k |   while (i < patternLength) | 
| 132 | 809k |   { | 
| 133 | 809k |     c = pattern[i++]; | 
| 134 |  |  | 
| 135 | 809k |     switch (state) | 
| 136 | 809k |     { | 
| 137 | 642k |       case LITERAL_STATE: | 
| 138 |  |  | 
| 139 |  |         // In literal state, the last char is always a literal. | 
| 140 | 642k |         if (i == patternLength) | 
| 141 | 522 |         { | 
| 142 | 522 |           currentLiteral.append(1, c); | 
| 143 |  |  | 
| 144 | 522 |           continue; | 
| 145 | 522 |         } | 
| 146 |  |  | 
| 147 | 641k |         if (c == ESCAPE_CHAR) | 
| 148 | 127k |         { | 
| 149 |  |           // peek at the next char. | 
| 150 | 127k |           if (pattern[i] == ESCAPE_CHAR) | 
| 151 | 1.11k |           { | 
| 152 | 1.11k |             currentLiteral.append(1, c); | 
| 153 | 1.11k |             i++; // move pointer | 
| 154 | 1.11k |           } | 
| 155 | 126k |           else | 
| 156 | 126k |           { | 
| 157 | 126k |             if (!currentLiteral.empty()) | 
| 158 | 30.9k |             { | 
| 159 | 30.9k |               patternConverters.push_back( | 
| 160 | 30.9k |                 LiteralPatternConverter::newInstance(currentLiteral)); | 
| 161 | 30.9k |               formattingInfos.push_back(FormattingInfo::getDefault()); | 
| 162 | 30.9k |               currentLiteral.erase(currentLiteral.begin(), currentLiteral.end()); | 
| 163 | 30.9k |             } | 
| 164 |  |  | 
| 165 | 126k |             currentLiteral.append(1, c); // append % | 
| 166 | 126k |             state = CONVERTER_STATE; | 
| 167 | 126k |             formattingInfo = FormattingInfo::getDefault(); | 
| 168 | 126k |           } | 
| 169 | 127k |         } | 
| 170 | 513k |         else | 
| 171 | 513k |         { | 
| 172 | 513k |           currentLiteral.append(1, c); | 
| 173 | 513k |         } | 
| 174 |  |  | 
| 175 | 641k |         break; | 
| 176 |  |  | 
| 177 | 158k |       case CONVERTER_STATE: | 
| 178 | 158k |         currentLiteral.append(1, c); | 
| 179 |  |  | 
| 180 | 158k |         switch (c) | 
| 181 | 158k |         { | 
| 182 | 32.0k |           case 0x2D: // '-' | 
| 183 | 32.0k |             formattingInfo = std::make_shared<FormattingInfo>( | 
| 184 | 32.0k |                   true, formattingInfo->getMinLength(), | 
| 185 | 32.0k |                   formattingInfo->getMaxLength()); | 
| 186 |  |  | 
| 187 | 32.0k |             break; | 
| 188 |  |  | 
| 189 | 2.01k |           case 0x2E: // '.' | 
| 190 | 2.01k |             state = DOT_STATE; | 
| 191 |  |  | 
| 192 | 2.01k |             break; | 
| 193 |  |  | 
| 194 | 124k |           default: | 
| 195 |  |  | 
| 196 | 124k |             if ((c >= 0x30 /* '0' */) && (c <= 0x39 /* '9' */)) | 
| 197 | 2.53k |             { | 
| 198 | 2.53k |               formattingInfo = std::make_shared<FormattingInfo>( | 
| 199 | 2.53k |                     formattingInfo->isLeftAligned(), c - 0x30 /* '0' */, | 
| 200 | 2.53k |                     formattingInfo->getMaxLength()); | 
| 201 | 2.53k |               state = MIN_STATE; | 
| 202 | 2.53k |               minDigitCount = 1; | 
| 203 | 2.53k |             } | 
| 204 | 122k |             else | 
| 205 | 122k |             { | 
| 206 | 122k |               i = finalizeConverter( | 
| 207 | 122k |                   c, pattern, i, currentLiteral, formattingInfo, | 
| 208 | 122k |                   rules, patternConverters, formattingInfos); | 
| 209 |  |  | 
| 210 |  |               // Next pattern is assumed to be a literal. | 
| 211 | 122k |               state = LITERAL_STATE; | 
| 212 | 122k |               formattingInfo = FormattingInfo::getDefault(); | 
| 213 |  |  | 
| 214 | 122k |               if (!currentLiteral.empty()) | 
| 215 | 0 |               { | 
| 216 | 0 |                 currentLiteral.erase(currentLiteral.begin(), currentLiteral.end()); | 
| 217 | 0 |               } | 
| 218 | 122k |             } | 
| 219 | 158k |         } // switch | 
| 220 |  |  | 
| 221 | 158k |         break; | 
| 222 |  |  | 
| 223 | 158k |       case MIN_STATE: | 
| 224 | 3.90k |         currentLiteral.append(1, c); | 
| 225 |  |  | 
| 226 | 3.90k |         if ((c >= 0x30 /* '0' */) && (c <= 0x39 /* '9' */) && minDigitCount < 3) | 
| 227 | 1.41k |         { | 
| 228 | 1.41k |           formattingInfo = std::make_shared<FormattingInfo>( | 
| 229 | 1.41k |                 formattingInfo->isLeftAligned(), | 
| 230 | 1.41k |                 (formattingInfo->getMinLength() * 10) + (c - 0x30 /* '0' */), | 
| 231 | 1.41k |                 formattingInfo->getMaxLength()); | 
| 232 | 1.41k |           ++minDigitCount; | 
| 233 | 1.41k |         } | 
| 234 | 2.48k |         else if (c == 0x2E /* '.' */) | 
| 235 | 680 |         { | 
| 236 | 680 |           state = DOT_STATE; | 
| 237 | 680 |         } | 
| 238 | 1.80k |         else | 
| 239 | 1.80k |         { | 
| 240 | 1.80k |           i = finalizeConverter( | 
| 241 | 1.80k |               c, pattern, i, currentLiteral, formattingInfo, | 
| 242 | 1.80k |               rules, patternConverters, formattingInfos); | 
| 243 | 1.80k |           state = LITERAL_STATE; | 
| 244 | 1.80k |           formattingInfo = FormattingInfo::getDefault(); | 
| 245 |  |  | 
| 246 | 1.80k |           if (!currentLiteral.empty()) | 
| 247 | 0 |           { | 
| 248 | 0 |             currentLiteral.erase(currentLiteral.begin(), currentLiteral.end()); | 
| 249 | 0 |           } | 
| 250 | 1.80k |         } | 
| 251 |  |  | 
| 252 | 3.90k |         break; | 
| 253 |  |  | 
| 254 | 2.68k |       case DOT_STATE: | 
| 255 | 2.68k |         currentLiteral.append(1, c); | 
| 256 |  |  | 
| 257 | 2.68k |         if ((c >= 0x30 /* '0' */) && (c <= 0x39 /* '9' */)) | 
| 258 | 1.53k |         { | 
| 259 | 1.53k |           formattingInfo = std::make_shared<FormattingInfo>( | 
| 260 | 1.53k |                 formattingInfo->isLeftAligned(), formattingInfo->getMinLength(), | 
| 261 | 1.53k |                 c - 0x30 /* '0' */); | 
| 262 | 1.53k |           state = MAX_STATE; | 
| 263 | 1.53k |           maxDigitCount = 1; | 
| 264 | 1.53k |         } | 
| 265 | 1.14k |         else | 
| 266 | 1.14k |         { | 
| 267 | 1.14k |           LogLog::error(LOG4CXX_STR("Error in pattern, was expecting digit.")); | 
| 268 |  |  | 
| 269 | 1.14k |           state = LITERAL_STATE; | 
| 270 | 1.14k |         } | 
| 271 |  |  | 
| 272 | 2.68k |         break; | 
| 273 |  |  | 
| 274 | 2.53k |       case MAX_STATE: | 
| 275 | 2.53k |         currentLiteral.append(1, c); | 
| 276 |  |  | 
| 277 | 2.53k |         if ((c >= 0x30 /* '0' */) && (c <= 0x39 /* '9' */) && maxDigitCount < 3) | 
| 278 | 1.04k |         { | 
| 279 | 1.04k |           formattingInfo = std::make_shared<FormattingInfo>( | 
| 280 | 1.04k |                 formattingInfo->isLeftAligned(), formattingInfo->getMinLength(), | 
| 281 | 1.04k |                 (formattingInfo->getMaxLength() * 10) + (c - 0x30 /* '0' */)); | 
| 282 | 1.04k |           ++maxDigitCount; | 
| 283 | 1.04k |         } | 
| 284 | 1.49k |         else | 
| 285 | 1.49k |         { | 
| 286 | 1.49k |           i = finalizeConverter( | 
| 287 | 1.49k |               c, pattern, i, currentLiteral, formattingInfo, | 
| 288 | 1.49k |               rules, patternConverters, formattingInfos); | 
| 289 | 1.49k |           state = LITERAL_STATE; | 
| 290 | 1.49k |           formattingInfo = FormattingInfo::getDefault(); | 
| 291 |  |  | 
| 292 | 1.49k |           if (!currentLiteral.empty()) | 
| 293 | 0 |           { | 
| 294 | 0 |             currentLiteral.erase(currentLiteral.begin(), currentLiteral.end()); | 
| 295 | 0 |           } | 
| 296 | 1.49k |         } | 
| 297 |  |  | 
| 298 | 2.53k |         break; | 
| 299 | 809k |     } // switch | 
| 300 | 809k |   } | 
| 301 |  |  | 
| 302 |  |   // while | 
| 303 | 3.76k |   if (currentLiteral.length() != 0) | 
| 304 | 786 |   { | 
| 305 | 786 |     patternConverters.push_back( | 
| 306 | 786 |       LiteralPatternConverter::newInstance(currentLiteral)); | 
| 307 | 786 |     formattingInfos.push_back(FormattingInfo::getDefault()); | 
| 308 | 786 |   } | 
| 309 | 3.76k | } | 
| 310 |  |  | 
| 311 |  |  | 
| 312 |  | PatternConverterPtr PatternParser::createConverter( | 
| 313 |  |   const LogString& converterId, | 
| 314 |  |   LogString& currentLiteral, | 
| 315 |  |   const PatternMap& rules, | 
| 316 |  |   std::vector<LogString>& options) | 
| 317 | 119k | { | 
| 318 |  |  | 
| 319 | 119k |   LogString converterName(converterId); | 
| 320 |  |  | 
| 321 | 370k |   for (size_t i = converterId.length(); i > 0; i--) | 
| 322 | 367k |   { | 
| 323 | 367k |     converterName = converterName.substr(0, i); | 
| 324 | 367k |     PatternMap::const_iterator iter = rules.find(converterName); | 
| 325 |  |  | 
| 326 | 367k |     if (iter != rules.end()) | 
| 327 | 116k |     { | 
| 328 | 116k |       currentLiteral.erase(currentLiteral.begin(), | 
| 329 | 116k |         currentLiteral.end() - (converterId.length() - i)); | 
| 330 | 116k |       return (iter->second)(options); | 
| 331 | 116k |     } | 
| 332 | 367k |   } | 
| 333 |  |  | 
| 334 | 3.25k |   LogLog::error(LogString(LOG4CXX_STR("Unrecognized format specifier ")) + converterId); | 
| 335 |  |  | 
| 336 | 3.25k |   return PatternConverterPtr(); | 
| 337 | 119k | } | 
| 338 |  |  | 
| 339 |  | size_t PatternParser::finalizeConverter( | 
| 340 |  |   logchar c, const LogString& pattern, size_t i, | 
| 341 |  |   LogString& currentLiteral, const FormattingInfoPtr& formattingInfo, | 
| 342 |  |   const PatternMap&  rules, | 
| 343 |  |   std::vector<PatternConverterPtr>& patternConverters, | 
| 344 |  |   std::vector<FormattingInfoPtr>&  formattingInfos) | 
| 345 | 125k | { | 
| 346 | 125k |   LogString convBuf; | 
| 347 | 125k |   i = extractConverter(c, pattern, i, convBuf, currentLiteral); | 
| 348 |  |  | 
| 349 | 125k |   if (convBuf.empty()) | 
| 350 | 5.98k |   { | 
| 351 | 5.98k |     LogLog::error(LOG4CXX_STR("Empty conversion specifier")); | 
| 352 | 5.98k |     patternConverters.push_back( | 
| 353 | 5.98k |       LiteralPatternConverter::newInstance(currentLiteral)); | 
| 354 | 5.98k |     formattingInfos.push_back(FormattingInfo::getDefault()); | 
| 355 | 5.98k |   } | 
| 356 | 119k |   else | 
| 357 | 119k |   { | 
| 358 | 119k |     LogString converterId(convBuf); | 
| 359 |  |  | 
| 360 | 119k |     std::vector<LogString> options; | 
| 361 | 119k |     i = extractOptions(pattern, i, options); | 
| 362 |  |  | 
| 363 | 119k |     PatternConverterPtr pc( | 
| 364 | 119k |       createConverter( | 
| 365 | 119k |         converterId, currentLiteral, rules, options)); | 
| 366 |  |  | 
| 367 | 119k |     if (pc == NULL) | 
| 368 | 3.25k |     { | 
| 369 | 3.25k |       LogString msg(LOG4CXX_STR("Unrecognized conversion specifier [")); | 
| 370 | 3.25k |       msg.append(converterId); | 
| 371 | 3.25k |       msg.append(LOG4CXX_STR("] in conversion pattern.")); | 
| 372 | 3.25k |       LogLog::error(msg); | 
| 373 | 3.25k |       patternConverters.push_back( | 
| 374 | 3.25k |         LiteralPatternConverter::newInstance(currentLiteral)); | 
| 375 | 3.25k |       formattingInfos.push_back(FormattingInfo::getDefault()); | 
| 376 | 3.25k |     } | 
| 377 | 116k |     else | 
| 378 | 116k |     { | 
| 379 | 116k |       patternConverters.push_back(pc); | 
| 380 | 116k |       formattingInfos.push_back(formattingInfo); | 
| 381 |  |  | 
| 382 | 116k |       if (currentLiteral.length() > 0) | 
| 383 | 24.6k |       { | 
| 384 | 24.6k |         patternConverters.push_back( | 
| 385 | 24.6k |           LiteralPatternConverter::newInstance(currentLiteral)); | 
| 386 | 24.6k |         formattingInfos.push_back(FormattingInfo::getDefault()); | 
| 387 | 24.6k |       } | 
| 388 | 116k |     } | 
| 389 | 119k |   } | 
| 390 |  |  | 
| 391 | 125k |   if (!currentLiteral.empty()) | 
| 392 | 33.9k |   { | 
| 393 | 33.9k |     currentLiteral.erase(currentLiteral.begin(), currentLiteral.end()); | 
| 394 | 33.9k |   } | 
| 395 |  |  | 
| 396 | 125k |   return i; | 
| 397 | 125k | } |