KiCad PCB EDA Suite
eda_pattern_match.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015-2017 Chris Pavlina <pavlina.chris@gmail.com>
5  * Copyright (C) 2015-2017 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <eda_pattern_match.h>
26 #include <wx/log.h>
27 #include <climits>
28 #include <make_unique.h>
29 
30 bool EDA_PATTERN_MATCH_SUBSTR::SetPattern( const wxString& aPattern )
31 {
32  m_pattern = aPattern;
33  return true;
34 }
35 
36 
37 wxString const& EDA_PATTERN_MATCH_SUBSTR::GetPattern() const
38 {
39  return m_pattern;
40 }
41 
42 
43 int EDA_PATTERN_MATCH_SUBSTR::Find( const wxString& aCandidate ) const
44 {
45  int loc = aCandidate.Find( m_pattern );
46 
47  return ( loc == wxNOT_FOUND ) ? EDA_PATTERN_NOT_FOUND : loc;
48 }
49 
50 
55 {
56  wxLogLevel m_old_level;
57 
58 public:
59  WX_LOGLEVEL_CONTEXT( wxLogLevel level )
60  {
61  m_old_level = wxLog::GetLogLevel();
62  wxLog::SetLogLevel( level );
63  }
64 
66  {
67  wxLog::SetLogLevel( m_old_level );
68  }
69 };
70 
71 
72 bool EDA_PATTERN_MATCH_REGEX::SetPattern( const wxString& aPattern )
73 {
74  m_pattern = aPattern;
75 
76  // Evil and undocumented: wxRegEx::Compile calls wxLogError on error, even
77  // though it promises to just return false. Silence the error.
78  WX_LOGLEVEL_CONTEXT ctx( wxLOG_FatalError );
79 
80  return m_regex.Compile( aPattern, wxRE_ADVANCED );
81 }
82 
83 
84 wxString const& EDA_PATTERN_MATCH_REGEX::GetPattern() const
85 {
86  return m_pattern;
87 }
88 
89 
90 int EDA_PATTERN_MATCH_REGEX::Find( const wxString& aCandidate ) const
91 {
92  if( m_regex.IsValid() )
93  {
94  if( m_regex.Matches( aCandidate ) )
95  {
96  size_t start, len;
97  m_regex.GetMatch( &start, &len, 0 );
98  return ( start > INT_MAX ) ? INT_MAX : start;
99  }
100  else
101  {
102  return EDA_PATTERN_NOT_FOUND;
103  }
104  }
105  else
106  {
107  int loc = aCandidate.Find( m_pattern );
108  return ( loc == wxNOT_FOUND ) ? EDA_PATTERN_NOT_FOUND : loc;
109  }
110 }
111 
112 
113 bool EDA_PATTERN_MATCH_WILDCARD::SetPattern( const wxString& aPattern )
114 {
115  m_wildcard_pattern = aPattern;
116 
117  // Compile the wildcard string to a regular expression
118  wxString regex;
119  regex.Alloc( 2 * aPattern.Length() ); // no need to keep resizing, we know the size roughly
120 
121  const wxString to_replace = wxT( ".*+?^${}()|[]/\\" );
122 
123  for( wxString::const_iterator it = aPattern.begin(); it < aPattern.end(); ++it )
124  {
125  wxUniChar c = *it;
126  if( c == '?' )
127  {
128  regex += wxT( "." );
129  }
130  else if( c == '*' )
131  {
132  regex += wxT( ".*" );
133  }
134  else if( to_replace.Find( c ) != wxNOT_FOUND )
135  {
136  regex += "\\";
137  regex += c;
138  }
139  else
140  {
141  regex += c;
142  }
143  }
144 
145  return EDA_PATTERN_MATCH_REGEX::SetPattern( regex );
146 }
147 
148 
150 {
151  return m_wildcard_pattern;
152 }
153 
154 
155 int EDA_PATTERN_MATCH_WILDCARD::Find( const wxString& aCandidate ) const
156 {
157  return EDA_PATTERN_MATCH_REGEX::Find( aCandidate );
158 }
159 
160 
162  : m_pattern( aPattern )
163 {
164  // Whatever syntax users prefer, it shall be matched.
165  AddMatcher( aPattern, std::make_unique<EDA_PATTERN_MATCH_REGEX>() );
166  AddMatcher( aPattern, std::make_unique<EDA_PATTERN_MATCH_WILDCARD>() );
167  // If any of the above matchers couldn't be created because the pattern
168  // syntax does not match, the substring will try its best.
169  AddMatcher( aPattern, std::make_unique<EDA_PATTERN_MATCH_SUBSTR>() );
170 }
171 
172 
173 bool EDA_COMBINED_MATCHER::Find( const wxString& aTerm, int& aMatchersTriggered, int& aPosition )
174 {
175  aPosition = EDA_PATTERN_NOT_FOUND;
176  aMatchersTriggered = 0;
177 
178  for( auto const& matcher : m_matchers )
179  {
180  int local_find = matcher->Find( aTerm );
181 
182  if ( local_find != EDA_PATTERN_NOT_FOUND )
183  {
184  aMatchersTriggered += 1;
185 
186  if ( local_find < aPosition || aPosition == EDA_PATTERN_NOT_FOUND )
187  {
188  aPosition = local_find;
189  }
190  }
191  }
192 
193  return aPosition != EDA_PATTERN_NOT_FOUND;
194 }
195 
196 
197 wxString const& EDA_COMBINED_MATCHER::GetPattern() const
198 {
199  return m_pattern;
200 }
201 
202 
204  const wxString &aPattern,
205  std::unique_ptr<EDA_PATTERN_MATCH> aMatcher )
206 {
207  if ( aMatcher->SetPattern( aPattern ) )
208  {
209  m_matchers.push_back( std::move( aMatcher ) );
210  }
211 }
std::vector< std::unique_ptr< EDA_PATTERN_MATCH > > m_matchers
wxString const & GetPattern() const
virtual wxString const & GetPattern() const override
Return the pattern passed to SetPattern().
virtual int Find(const wxString &aCandidate) const override
Return the location of a match iff a given candidate string matches the set pattern.
virtual bool SetPattern(const wxString &aPattern) override
Set the pattern against which candidates will be matched.
void AddMatcher(const wxString &aPattern, std::unique_ptr< EDA_PATTERN_MATCH > aMatcher)
virtual bool SetPattern(const wxString &aPattern) override
Set the pattern against which candidates will be matched.
Abstract pattern-matching tool and implementations.
virtual wxString const & GetPattern() const override
Return the pattern passed to SetPattern().
virtual bool SetPattern(const wxString &aPattern) override
Set the pattern against which candidates will be matched.
bool Find(const wxString &aTerm, int &aMatchersTriggered, int &aPosition)
virtual int Find(const wxString &aCandidate) const override
Return the location of a match iff a given candidate string matches the set pattern.
static const int EDA_PATTERN_NOT_FOUND
virtual wxString const & GetPattern() const override
Return the pattern passed to SetPattern().
Context class to set wx loglevel for a block, and always restore it at the end.
Implementation of std::make_unique for pre C++14 compilation environments.
virtual int Find(const wxString &aCandidate) const override
Return the location of a match iff a given candidate string matches the set pattern.
WX_LOGLEVEL_CONTEXT(wxLogLevel level)
EDA_COMBINED_MATCHER(const wxString &aPattern)