1<?php
2/*
3** Zabbix
4** Copyright (C) 2001-2021 Zabbix SIA
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2 of the License, or
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU General Public License
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19**/
20
21
22/**
23 *  A parser for function macros like "{host.item.func()}".
24 */
25class CFunctionMacroParser extends CParser {
26
27	/**
28	 * An options array.
29	 *
30	 * Supported options:
31	 *   '18_simple_checks' => true		with support for old-style simple checks like "ftp,{$PORT}"
32	 *
33	 * @var array
34	 */
35	private $options = ['18_simple_checks' => false];
36
37	/**
38	 * Parser for item keys.
39	 *
40	 * @var CItemkey
41	 */
42	private $item_key_parser;
43
44	/**
45	 * Parser for trigger functions.
46	 *
47	 * @var CFunctionParser
48	 */
49	private $function_parser;
50
51	/**
52	 * Parser for host names.
53	 *
54	 * @var CHostNameParser
55	 */
56	private $host_name_parser;
57
58	private $host = '';
59	private $item = '';
60	private $function = '';
61
62	/**
63	 * @param array $options
64	 */
65	public function __construct($options = []) {
66		if (array_key_exists('18_simple_checks', $options)) {
67			$this->options['18_simple_checks'] = $options['18_simple_checks'];
68		}
69
70		$this->item_key_parser = new CItemKey(['18_simple_checks' => $this->options['18_simple_checks']]);
71		$this->function_parser = new CFunctionParser();
72		$this->host_name_parser = new CHostNameParser();
73	}
74
75	/**
76	 * @param string    $source
77	 * @param int       $pos
78	 *
79	 * @return int
80	 */
81	public function parse($source, $pos = 0) {
82		$this->length = 0;
83		$this->match = '';
84		$this->host = '';
85		$this->item = '';
86		$this->function = '';
87
88		$p = $pos;
89
90		if (!isset($source[$p]) || $source[$p] !== '{') {
91			return self::PARSE_FAIL;
92		}
93		$p++;
94
95		if (!$this->parseHost($source, $p)) {
96			return self::PARSE_FAIL;
97		}
98
99		if (!isset($source[$p]) || $source[$p] !== ':') {
100			return self::PARSE_FAIL;
101		}
102		$p++;
103
104		$p2 = $p;
105
106		if ($this->item_key_parser->parse($source, $p) == CParser::PARSE_FAIL) {
107			return self::PARSE_FAIL;
108		}
109		$p += $this->item_key_parser->getLength();
110
111		// for instance, agent.ping.last(0)
112		if ($this->item_key_parser->getParamsNum() == 0 && isset($source[$p]) && $source[$p] == '(') {
113			for (; $p > $p2 && $source[$p] != '.'; $p--) {
114				// Code is not missing here.
115			}
116
117			if ($p == $p2) {
118				return self::PARSE_FAIL;
119			}
120		}
121		$p3 = $p;
122
123		if (!isset($source[$p]) || $source[$p] !== '.') {
124			return self::PARSE_FAIL;
125		}
126		$p++;
127
128		if ($this->function_parser->parse($source, $p) == CParser::PARSE_FAIL) {
129			return self::PARSE_FAIL;
130		}
131		$p += $this->function_parser->getLength();
132
133		if (!isset($source[$p]) || $source[$p] !== '}') {
134			return self::PARSE_FAIL;
135		}
136		$p++;
137
138		$this->length = $p - $pos;
139		$this->match = substr($source, $pos, $this->length);
140		$this->host = substr($source, $pos + 1, $p2 - $pos - 2);
141		$this->item = substr($source, $p2, $p3 - $p2);
142		$this->function = $this->function_parser->getMatch();
143
144		return (isset($source[$pos + $this->length]) ? self::PARSE_SUCCESS_CONT : self::PARSE_SUCCESS);
145	}
146
147	/**
148	 * Parses a host in a trigger function macro constant and moves a position ($pos) on a next symbol after the host.
149	 *
150	 * @param string	$source
151	 * @param int		$pos
152	 *
153	 * @return bool
154	 */
155	protected function parseHost($source, &$pos) {
156		if ($this->host_name_parser->parse($source, $pos) == self::PARSE_FAIL) {
157			return false;
158		}
159
160		$pos += $this->host_name_parser->getLength();
161
162		return true;
163	}
164
165	/**
166	 * Returns parsed host.
167	 *
168	 * @return string
169	 */
170	public function getHost() {
171		return $this->host;
172	}
173
174	/**
175	 * Returns parsed item.
176	 *
177	 * @return string
178	 */
179	public function getItem() {
180		return $this->item;
181	}
182
183	/**
184	 * Returns parsed function.
185	 *
186	 * @return string
187	 */
188	public function getFunction() {
189		return $this->function;
190	}
191}
192