blob: a363adb8064a305c422944ef0e5050b1aa770217 [file] [log] [blame]
Qiuhan Ding699725d2015-05-24 01:41:09 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2015 Regents of the University of California.
4 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#include "regex-repeat-matcher.hpp"
23
24#include "regex-backref-matcher.hpp"
25#include "regex-component-set-matcher.hpp"
26
27namespace ndn {
28
29RegexRepeatMatcher::RegexRepeatMatcher(const std::string& expr,
30 shared_ptr<RegexBackrefManager> backrefManager,
31 size_t indicator)
32 : RegexMatcher(expr, EXPR_REPEAT_PATTERN, backrefManager)
33 , m_indicator(indicator)
34{
35 compile();
36}
37
38RegexRepeatMatcher::~RegexRepeatMatcher()
39{
40}
41
42bool
43RegexRepeatMatcher::match(const Name& name, size_t offset, size_t len)
44{
45 m_matchResult.clear();
46
47 if (0 == m_repeatMin)
48 if (0 == len)
49 return true;
50
51 if (recursiveMatch(0, name, offset, len)) {
52 for (size_t i = offset; i < offset + len; i++)
53 m_matchResult.push_back(name.get(i));
54 return true;
55 }
56 else
57 return false;
58}
59
60void
61RegexRepeatMatcher::compile()
62{
63 shared_ptr<RegexMatcher> matcher;
64
65 if ('(' == m_expr[0]) {
66 matcher = make_shared<RegexBackrefMatcher>(m_expr.substr(0, m_indicator), m_backrefManager);
67 m_backrefManager->pushRef(matcher);
68 dynamic_pointer_cast<RegexBackrefMatcher>(matcher)->lateCompile();
69 }
70 else{
71 matcher = make_shared<RegexComponentSetMatcher>(m_expr.substr(0, m_indicator),
72 m_backrefManager);
73 }
74 m_matchers.push_back(matcher);
75
76 parseRepetition();
77}
78
79bool
80RegexRepeatMatcher::parseRepetition()
81{
82 size_t exprSize = m_expr.size();
83 const size_t MAX_REPETITIONS = std::numeric_limits<size_t>::max();
84
85 if (exprSize == m_indicator) {
86 m_repeatMin = 1;
87 m_repeatMax = 1;
88
89 return true;
90 }
91 else {
92 if (exprSize == (m_indicator + 1)) {
93 if ('?' == m_expr[m_indicator]) {
94 m_repeatMin = 0;
95 m_repeatMax = 1;
96 return true;
97 }
98 if ('+' == m_expr[m_indicator]) {
99 m_repeatMin = 1;
100 m_repeatMax = MAX_REPETITIONS;
101 return true;
102 }
103 if ('*' == m_expr[m_indicator]) {
104 m_repeatMin = 0;
105 m_repeatMax = MAX_REPETITIONS;
106 return true;
107 }
108 }
109 else {
110 std::string repeatStruct = m_expr.substr(m_indicator, exprSize - m_indicator);
111 size_t rsSize = repeatStruct.size();
112 size_t min = 0;
113 size_t max = 0;
114
115 if (boost::regex_match(repeatStruct, boost::regex("\\{[0-9]+,[0-9]+\\}"))) {
116 size_t separator = repeatStruct.find_first_of(',', 0);
117 min = atoi(repeatStruct.substr(1, separator - 1).c_str());
118 max = atoi(repeatStruct.substr(separator + 1, rsSize - separator - 2).c_str());
119 }
120 else if (boost::regex_match(repeatStruct, boost::regex("\\{,[0-9]+\\}"))) {
121 size_t separator = repeatStruct.find_first_of(',', 0);
122 min = 0;
123 max = atoi(repeatStruct.substr(separator + 1, rsSize - separator - 2).c_str());
124 }
125 else if (boost::regex_match(repeatStruct, boost::regex("\\{[0-9]+,\\}"))) {
126 size_t separator = repeatStruct.find_first_of(',', 0);
127 min = atoi(repeatStruct.substr(1, separator).c_str());
128 max = MAX_REPETITIONS;
129 }
130 else if (boost::regex_match(repeatStruct, boost::regex("\\{[0-9]+\\}"))) {
131 min = atoi(repeatStruct.substr(1, rsSize - 1).c_str());
132 max = min;
133 }
134 else
135 throw Error("Error: RegexRepeatMatcher.ParseRepetition(): Unrecognized format " + m_expr);
136
137 if (min > MAX_REPETITIONS || max > MAX_REPETITIONS || min > max)
138 throw Error("Error: RegexRepeatMatcher.ParseRepetition(): Wrong number " + m_expr);
139
140 m_repeatMin = min;
141 m_repeatMax = max;
142
143 return true;
144 }
145 }
146 return false;
147}
148
149bool
150RegexRepeatMatcher::recursiveMatch(size_t repeat, const Name& name, size_t offset, size_t len)
151{
152 ssize_t tried = len;
153 shared_ptr<RegexMatcher> matcher = m_matchers[0];
154
155 if (0 < len && repeat >= m_repeatMax) {
156 return false;
157 }
158
159 if (0 == len && repeat < m_repeatMin) {
160 return false;
161 }
162
163 if (0 == len && repeat >= m_repeatMin) {
164 return true;
165 }
166
167 while (tried >= 0) {
168 if (matcher->match(name, offset, tried) &&
169 recursiveMatch(repeat + 1, name, offset + tried, len - tried))
170 return true;
171 tried--;
172 }
173
174 return false;
175}
176
177} // namespace ndn
178