PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/log4php/Helper/PatternParser.php

https://github.com/ehutson/log4php
PHP | 349 lines | 260 code | 22 blank | 67 comment | 46 complexity | d2f48cb5c521eb4bdf4dc5d10c8156a1 MD5 | raw file
  1. <?php
  2. namespace log4php\Helper;
  3. use log4php\Helper\FormattingInfo,
  4. log4php\Helper\BasicPatternConverter,
  5. log4php\Helper\CategoryPatternConverter,
  6. log4php\Helper\ClassNamePatternConverter,
  7. log4php\Helper\DatePatternConverter,
  8. log4php\Helper\FormattingInfo,
  9. log4php\Helper\LiteralPatternConverter,
  10. log4php\Helper\LocationPatternConverter,
  11. log4php\Helper\PatternConverter;
  12. /**
  13. * Licensed to the Apache Software Foundation (ASF) under one or more
  14. * contributor license agreements. See the NOTICE file distributed with
  15. * this work for additional information regarding copyright ownership.
  16. * The ASF licenses this file to You under the Apache License, Version 2.0
  17. * (the "License"); you may not use this file except in compliance with
  18. * the License. You may obtain a copy of the License at
  19. *
  20. * http://www.apache.org/licenses/LICENSE-2.0
  21. *
  22. * Unless required by applicable law or agreed to in writing, software
  23. * distributed under the License is distributed on an "AS IS" BASIS,
  24. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  25. * See the License for the specific language governing permissions and
  26. * limitations under the License.
  27. *
  28. * @package log4php
  29. */
  30. /**
  31. * Most of the work of the {@link PatternLayout} class
  32. * is delegated to the {@link PatternParser} class.
  33. *
  34. * <p>It is this class that parses conversion patterns and creates
  35. * a chained list of {@link PatternConverter} converters.</p>
  36. *
  37. * @version $Revision: 1163520 $
  38. * @package log4php
  39. * @subpackage helpers
  40. *
  41. * @since 0.3
  42. */
  43. class PatternParser
  44. {
  45. const ESCAPE_CHAR = '%';
  46. const LITERAL_STATE = 0;
  47. const CONVERTER_STATE = 1;
  48. const MINUS_STATE = 2;
  49. const DOT_STATE = 3;
  50. const MIN_STATE = 4;
  51. const MAX_STATE = 5;
  52. const FULL_LOCATION_CONVERTER = 1000;
  53. const METHOD_LOCATION_CONVERTER = 1001;
  54. const CLASS_LOCATION_CONVERTER = 1002;
  55. const FILE_LOCATION_CONVERTER = 1003;
  56. const LINE_LOCATION_CONVERTER = 1004;
  57. const RELATIVE_TIME_CONVERTER = 2000;
  58. const THREAD_CONVERTER = 2001;
  59. const LEVEL_CONVERTER = 2002;
  60. const NDC_CONVERTER = 2003;
  61. const MESSAGE_CONVERTER = 2004;
  62. const DATE_FORMAT_ISO8601 = 'Y-m-d H:i:s,u';
  63. const DATE_FORMAT_ABSOLUTE = 'H:i:s';
  64. const DATE_FORMAT_DATE = 'd M Y H:i:s,u';
  65. private $state;
  66. private $currentLiteral;
  67. private $patternLength;
  68. private $i;
  69. /**
  70. * @var PatternConverter
  71. */
  72. private $head = null;
  73. /**
  74. * @var PatternConverter
  75. */
  76. private $tail = null;
  77. /**
  78. * @var FormattingInfo
  79. */
  80. private $formattingInfo;
  81. /**
  82. * @var string pattern to parse
  83. */
  84. private $pattern;
  85. /**
  86. * Constructor
  87. *
  88. * @param string $pattern
  89. */
  90. public function __construct($pattern)
  91. {
  92. $this->pattern = $pattern;
  93. $this->patternLength = strlen($pattern);
  94. $this->formattingInfo = new FormattingInfo();
  95. $this->state = self::LITERAL_STATE;
  96. }
  97. /**
  98. * @param PatternConverter $pc
  99. */
  100. public function addToList($pc)
  101. {
  102. if ($this->head == null) {
  103. $this->head = $pc;
  104. $this->tail = $this->head;
  105. } else {
  106. $this->tail->next = $pc;
  107. $this->tail = $this->tail->next;
  108. }
  109. }
  110. /**
  111. * @return string
  112. */
  113. public function extractOption()
  114. {
  115. if (($this->i < $this->patternLength) and ($this->pattern{$this->i} == '{')) {
  116. $end = strpos($this->pattern, '}', $this->i);
  117. if ($end !== false) {
  118. $r = substr($this->pattern, ($this->i + 1),
  119. ($end - $this->i - 1));
  120. $this->i = $end + 1;
  121. return $r;
  122. }
  123. }
  124. return null;
  125. }
  126. /**
  127. * The option is expected to be in decimal and positive. In case of
  128. * error, zero is returned.
  129. */
  130. public function extractPrecisionOption()
  131. {
  132. $opt = $this->extractOption();
  133. $r = 0;
  134. if ($opt !== null) {
  135. if (is_numeric($opt)) {
  136. $r = (int) $opt;
  137. if ($r <= 0) {
  138. $r = 0;
  139. }
  140. }
  141. }
  142. return $r;
  143. }
  144. /** Parser.
  145. *
  146. * @return PatternConverter Returns $this->head.
  147. */
  148. public function parse()
  149. {
  150. $c = '';
  151. $this->i = 0;
  152. $this->currentLiteral = '';
  153. while ($this->i < $this->patternLength) {
  154. $c = $this->pattern{$this->i++};
  155. switch ($this->state) {
  156. case self::LITERAL_STATE:
  157. // In literal state, the last char is always a literal.
  158. if ($this->i == $this->patternLength) {
  159. $this->currentLiteral .= $c;
  160. continue;
  161. }
  162. if ($c == self::ESCAPE_CHAR) {
  163. // peek at the next char.
  164. switch ($this->pattern{$this->i}) {
  165. case self::ESCAPE_CHAR:
  166. $this->currentLiteral .= $c;
  167. $this->i++; // move pointer
  168. break;
  169. case 'n':
  170. $this->currentLiteral .= PHP_EOL;
  171. $this->i++; // move pointer
  172. break;
  173. default:
  174. if (strlen($this->currentLiteral) != 0) {
  175. $this->addToList(new LiteralPatternConverter($this->currentLiteral));
  176. }
  177. $this->currentLiteral = $c;
  178. $this->state = self::CONVERTER_STATE;
  179. $this->formattingInfo->reset();
  180. }
  181. } else {
  182. $this->currentLiteral .= $c;
  183. }
  184. break;
  185. case self::CONVERTER_STATE:
  186. $this->currentLiteral .= $c;
  187. switch ($c) {
  188. case '-':
  189. $this->formattingInfo->leftAlign = true;
  190. break;
  191. case '.':
  192. $this->state = self::DOT_STATE;
  193. break;
  194. default:
  195. if (ord($c) >= ord('0') and ord($c) <= ord('9')) {
  196. $this->formattingInfo->min = ord($c) - ord('0');
  197. $this->state = self::MIN_STATE;
  198. } else {
  199. $this->finalizeConverter($c);
  200. }
  201. } // switch
  202. break;
  203. case self::MIN_STATE:
  204. $this->currentLiteral .= $c;
  205. if (ord($c) >= ord('0') and ord($c) <= ord('9')) {
  206. $this->formattingInfo->min = ($this->formattingInfo->min * 10) + (ord($c) - ord('0'));
  207. } else if ($c == '.') {
  208. $this->state = self::DOT_STATE;
  209. } else {
  210. $this->finalizeConverter($c);
  211. }
  212. break;
  213. case self::DOT_STATE:
  214. $this->currentLiteral .= $c;
  215. if (ord($c) >= ord('0') and ord($c) <= ord('9')) {
  216. $this->formattingInfo->max = ord($c) - ord('0');
  217. $this->state = self::MAX_STATE;
  218. } else {
  219. $this->state = self::LITERAL_STATE;
  220. }
  221. break;
  222. case self::MAX_STATE:
  223. $this->currentLiteral .= $c;
  224. if (ord($c) >= ord('0') and ord($c) <= ord('9')) {
  225. $this->formattingInfo->max = ($this->formattingInfo->max * 10) + (ord($c) - ord('0'));
  226. } else {
  227. $this->finalizeConverter($c);
  228. $this->state = self::LITERAL_STATE;
  229. }
  230. break;
  231. } // switch
  232. } // while
  233. if (strlen($this->currentLiteral) != 0) {
  234. $this->addToList(new LiteralPatternConverter($this->currentLiteral));
  235. }
  236. return $this->head;
  237. }
  238. public function finalizeConverter($c)
  239. {
  240. $pc = null;
  241. switch ($c) {
  242. case 'c':
  243. $pc = new CategoryPatternConverter($this->formattingInfo, $this->extractPrecisionOption());
  244. $this->currentLiteral = '';
  245. break;
  246. case 'C':
  247. $pc = new ClassNamePatternConverter($this->formattingInfo, self::CLASS_LOCATION_CONVERTER);
  248. $this->currentLiteral = '';
  249. break;
  250. case 'd':
  251. $dateFormatStr = self::DATE_FORMAT_ISO8601; // ISO8601_DATE_FORMAT;
  252. $dOpt = $this->extractOption();
  253. if ($dOpt !== null)
  254. $dateFormatStr = $dOpt;
  255. if ($dateFormatStr == 'ISO8601') {
  256. $df = self::DATE_FORMAT_ISO8601;
  257. } else if ($dateFormatStr == 'ABSOLUTE') {
  258. $df = self::DATE_FORMAT_ABSOLUTE;
  259. } else if ($dateFormatStr == 'DATE') {
  260. $df = self::DATE_FORMAT_DATE;
  261. } else {
  262. $df = $dateFormatStr;
  263. if ($df == null) {
  264. $df = self::DATE_FORMAT_ISO8601;
  265. }
  266. }
  267. $pc = new DatePatternConverter($this->formattingInfo, $df);
  268. $this->currentLiteral = '';
  269. break;
  270. case 'F':
  271. $pc = new LocationPatternConverter($this->formattingInfo, self::FILE_LOCATION_CONVERTER);
  272. $this->currentLiteral = '';
  273. break;
  274. case 'l':
  275. $pc = new LocationPatternConverter($this->formattingInfo, self::FULL_LOCATION_CONVERTER);
  276. $this->currentLiteral = '';
  277. break;
  278. case 'L':
  279. $pc = new LocationPatternConverter($this->formattingInfo, self::LINE_LOCATION_CONVERTER);
  280. $this->currentLiteral = '';
  281. break;
  282. case 'm':
  283. $pc = new BasicPatternConverter($this->formattingInfo, self::MESSAGE_CONVERTER);
  284. $this->currentLiteral = '';
  285. break;
  286. case 'M':
  287. $pc = new LocationPatternConverter($this->formattingInfo, self::METHOD_LOCATION_CONVERTER);
  288. $this->currentLiteral = '';
  289. break;
  290. case 'p':
  291. $pc = new BasicPatternConverter($this->formattingInfo, self::LEVEL_CONVERTER);
  292. $this->currentLiteral = '';
  293. break;
  294. case 'r':
  295. $pc = new BasicPatternConverter($this->formattingInfo, self::RELATIVE_TIME_CONVERTER);
  296. $this->currentLiteral = '';
  297. break;
  298. case 't':
  299. $pc = new BasicPatternConverter($this->formattingInfo, self::THREAD_CONVERTER);
  300. $this->currentLiteral = '';
  301. break;
  302. case 'x':
  303. $pc = new BasicPatternConverter($this->formattingInfo, self::NDC_CONVERTER);
  304. $this->currentLiteral = '';
  305. break;
  306. case 'X':
  307. $xOpt = $this->extractOption();
  308. $pc = new MDCPatternConverter($this->formattingInfo, $xOpt);
  309. $this->currentLiteral = '';
  310. break;
  311. default:
  312. $pc = new LiteralPatternConverter($this->currentLiteral);
  313. $this->currentLiteral = '';
  314. }
  315. $this->addConverter($pc);
  316. }
  317. public function addConverter($pc)
  318. {
  319. $this->currentLiteral = '';
  320. // Add the pattern converter to the list.
  321. $this->addToList($pc);
  322. // Next pattern is assumed to be a literal.
  323. $this->state = self::LITERAL_STATE;
  324. // Reset formatting info
  325. $this->formattingInfo->reset();
  326. }
  327. }