1 //===-- LogFilterRegex.cpp --------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "LogFilterRegex.h"
10
11 #include "DNBLog.h"
12 #include "LogMessage.h"
13
14 // Enable enhanced mode if it is available. This allows for things like
15 // \d for digit, \s for space, and many more, but it isn't available
16 // everywhere.
17 #if defined(REG_ENHANCED)
18 #define DEFAULT_COMPILE_FLAGS (REG_ENHANCED | REG_EXTENDED)
19 #else
20 #define DEFAULT_COMPILE_FLAGS (REG_EXTENDED)
21 #endif
22
LogFilterRegex(bool match_accepts,FilterTarget filter_target,const std::string & regex)23 LogFilterRegex::LogFilterRegex(bool match_accepts, FilterTarget filter_target,
24 const std::string ®ex)
25 : LogFilter(match_accepts), m_filter_target(filter_target),
26 m_regex_text(regex), m_regex(), m_is_valid(false), m_error_text() {
27 // Clear it.
28 memset(&m_regex, 0, sizeof(m_regex));
29
30 // Compile it.
31 if (!regex.empty()) {
32 auto comp_err = ::regcomp(&m_regex, regex.c_str(), DEFAULT_COMPILE_FLAGS);
33 m_is_valid = (comp_err == 0);
34 if (!m_is_valid) {
35 char buffer[256];
36 buffer[0] = '\0';
37 ::regerror(comp_err, &m_regex, buffer, sizeof(buffer));
38 m_error_text = buffer;
39 }
40 }
41 }
42
~LogFilterRegex()43 LogFilterRegex::~LogFilterRegex() {
44 if (m_is_valid) {
45 // Free the regex internals.
46 regfree(&m_regex);
47 }
48 }
49
DoesMatch(const LogMessage & message) const50 bool LogFilterRegex::DoesMatch(const LogMessage &message) const {
51 switch (m_filter_target) {
52 case eFilterTargetActivity:
53 // Empty fields never match a condition.
54 if (!message.HasActivity())
55 return false;
56 return ::regexec(&m_regex, message.GetActivity(), 0, nullptr, 0) == 0;
57 case eFilterTargetActivityChain:
58 // Empty fields never match a condition.
59 if (!message.HasActivity())
60 return false;
61 return ::regexec(&m_regex, message.GetActivityChain().c_str(), 0, nullptr,
62 0) == 0;
63 case eFilterTargetCategory:
64 // Empty fields never match a condition.
65 if (!message.HasCategory())
66 return false;
67 return ::regexec(&m_regex, message.GetCategory(), 0, nullptr, 0) == 0;
68 case eFilterTargetMessage: {
69 const char *message_text = message.GetMessage();
70 if (!message_text) {
71 DNBLogThreadedIf(LOG_DARWIN_LOG,
72 "LogFilterRegex: regex "
73 "\"%s\" no match due to nullptr message.",
74 m_regex_text.c_str());
75 return false;
76 }
77
78 bool match = ::regexec(&m_regex, message_text, 0, nullptr, 0) == 0;
79 DNBLogThreadedIf(LOG_DARWIN_LOG, "LogFilterRegex: regex "
80 "\"%s\" %s message \"%s\".",
81 m_regex_text.c_str(), match ? "matches" : "does not match",
82 message_text);
83 return match;
84 }
85 case eFilterTargetSubsystem:
86 // Empty fields never match a condition.
87 if (!message.HasSubsystem())
88 return false;
89 return ::regexec(&m_regex, message.GetSubsystem(), 0, nullptr, 0) == 0;
90 default:
91 // We don't know this type.
92 return false;
93 }
94 }
95