@@ -116,9 +116,81 @@ std::string Settings::Suppressions::parseFile(std::istream &istr)
116116 return " " ;
117117}
118118
119+ bool Settings::Suppressions::FileMatcher::match (const std::string &pattern, const std::string &name)
120+ {
121+ const char *p = pattern.c_str ();
122+ const char *n = name.c_str ();
123+ std::list<std::pair<const char *, const char *> > backtrack;
124+
125+ for (;;) {
126+ bool matching = true ;
127+ while (*p != ' \0 ' && matching) {
128+ switch (*p) {
129+ case ' *' :
130+ // Step forward until we match the next character after *
131+ while (*n != ' \0 ' && *n != p[1 ]) {
132+ n++;
133+ }
134+ if (*n != ' \0 ' ) {
135+ // If this isn't the last possibility, save it for later
136+ backtrack.push_back (std::make_pair (p, n));
137+ }
138+ break ;
139+ case ' ?' :
140+ // Any character matches unless we're at the end of the name
141+ if (*n != ' \0 ' ) {
142+ n++;
143+ } else {
144+ matching = false ;
145+ }
146+ break ;
147+ default :
148+ // Non-wildcard characters match literally
149+ if (*n == *p) {
150+ n++;
151+ } else {
152+ matching = false ;
153+ }
154+ break ;
155+ }
156+ p++;
157+ }
158+
159+ // If we haven't failed matching and we've reached the end of the name, then success
160+ if (matching && *n == ' \0 ' ) {
161+ return true ;
162+ }
163+
164+ // If there are no other paths to tray, then fail
165+ if (backtrack.empty ()) {
166+ return false ;
167+ }
168+
169+ // Restore pointers from backtrack stack
170+ p = backtrack.back ().first ;
171+ n = backtrack.back ().second ;
172+ backtrack.pop_back ();
173+
174+ // Advance name pointer by one because the current position didn't work
175+ n++;
176+ }
177+ }
178+
119179std::string Settings::Suppressions::FileMatcher::addFile (const std::string &name, unsigned int line)
120180{
121- _files[name].insert (line);
181+ if (name.find_first_of (" *?" ) != std::string::npos) {
182+ for (std::string::const_iterator i = name.begin (); i != name.end (); ++i) {
183+ if (*i == ' *' ) {
184+ std::string::const_iterator j = i + 1 ;
185+ if (j != name.end () && (*j == ' *' || *j == ' ?' )) {
186+ return " Failed to add suppression. Syntax error in glob." ;
187+ }
188+ }
189+ }
190+ _globs[name].insert (line);
191+ } else {
192+ _files[name].insert (line);
193+ }
122194 return " " ;
123195}
124196
@@ -128,14 +200,26 @@ bool Settings::Suppressions::FileMatcher::isSuppressed(const std::string &file,
128200 if (_files.find (" " ) != _files.end ())
129201 return true ;
130202
131- if (_files.find (file) == _files.end ())
203+ std::set<unsigned int > lineset;
204+
205+ std::map<std::string, std::set<unsigned int > >::const_iterator f = _files.find (file);
206+ if (f != _files.end ()) {
207+ lineset.insert (f->second .begin (), f->second .end ());
208+ }
209+ for (std::map<std::string, std::set<unsigned int > >::iterator g = _globs.begin (); g != _globs.end (); ++g) {
210+ if (match (g->first , file)) {
211+ lineset.insert (g->second .begin (), g->second .end ());
212+ }
213+ }
214+
215+ if (lineset.empty ())
132216 return false ;
133217
134218 // Check should all errors in this file be filtered out
135- if (std:: find (_files[file]. begin (), _files[file]. end (), 0U ) != _files[file] .end ())
219+ if (lineset. find (0U ) != lineset .end ())
136220 return true ;
137221
138- if (std:: find (_files[file]. begin (), _files[file]. end (), line) == _files[file] .end ())
222+ if (lineset. find (line) == lineset .end ())
139223 return false ;
140224
141225 return true ;
0 commit comments