Merge pull request #218 from tweksteen/optional_re2

Add option to not rely on RE2
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d8f6fcc..ac07c0c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,18 +9,23 @@
 option(BLOATY_ENABLE_UBSAN "Enable undefined behavior sanitizer." OFF)
 option(BLOATY_ENABLE_CMAKETARGETS "Enable installing cmake target files." ON)
 option(BLOATY_ENABLE_BUILDID "Enable build id." ON)
+option(BLOATY_ENABLE_RE2 "Enable the support for regular expression functions." ON)
 
 if(UNIX)
 find_package(PkgConfig)
 if(${PKG_CONFIG_FOUND})
-pkg_search_module(RE2 re2)
+if(BLOATY_ENABLE_RE2)
+  pkg_search_module(RE2 re2)
+endif(BLOATY_ENABLE_RE2)
 pkg_search_module(CAPSTONE capstone)
 pkg_search_module(PROTOBUF protobuf)
-if(${RE2_FOUND})
-  MESSAGE(STATUS "System re2 found, using")
-else(${RE2_FOUND})
-  MESSAGE(STATUS "System re2 not found, using bundled version")
-endif(${RE2_FOUND})
+if(BLOATY_ENABLE_RE2)
+  if(${RE2_FOUND})
+    MESSAGE(STATUS "System re2 found, using")
+  else(${RE2_FOUND})
+    MESSAGE(STATUS "System re2 not found, using bundled version")
+  endif(${RE2_FOUND})
+endif(BLOATY_ENABLE_RE2)
 if(${CAPSTONE_FOUND})
   MESSAGE(STATUS "System capstone found, using")
 else(${CAPSTONE_FOUND})
@@ -53,15 +58,20 @@
 # Add third_party libraries, disabling as much as we can of their builds.
 
 add_definitions(-D_LIBCXXABI_FUNC_VIS=)  # For Demumble.
+if(BLOATY_ENABLE_RE2)
+  add_definitions(-DUSE_RE2)
+endif(BLOATY_ENABLE_RE2)
 
 if(UNIX)
-  if(${RE2_FOUND})
-    include_directories(${RE2_INCLUDE_DIRS})
-  else(${RE2_FOUND})
-    set(RE2_BUILD_TESTING OFF CACHE BOOL "enable testing for RE2" FORCE)
-    add_subdirectory(third_party/re2)
-    include_directories(third_party/re2)
-  endif(${RE2_FOUND})
+  if(BLOATY_ENABLE_RE2)
+    if(${RE2_FOUND})
+      include_directories(${RE2_INCLUDE_DIRS})
+    else(${RE2_FOUND})
+      set(RE2_BUILD_TESTING OFF CACHE BOOL "enable testing for RE2" FORCE)
+      add_subdirectory(third_party/re2)
+      include_directories(third_party/re2)
+    endif(${RE2_FOUND})
+  endif(BLOATY_ENABLE_RE2)
   if(${CAPSTONE_FOUND})
     include_directories(${CAPSTONE_INCLUDE_DIRS})
   else(${CAPSTONE_FOUND})
@@ -79,11 +89,13 @@
     include_directories(SYSTEM third_party/protobuf/src)
   endif(${PROTOBUF_FOUND})
 else(UNIX)
-  add_subdirectory(third_party/re2)
+  if(BLOATY_ENABLE_RE2)
+    add_subdirectory(third_party/re2)
+    include_directories(third_party/re2)
+  endif(BLOATY_ENABLE_RE2)
   add_subdirectory(third_party/capstone)
-  add_subdirectory(third_party/protobuf/cmake)
-  include_directories(third_party/re2)
   include_directories(third_party/capstone/include)
+  add_subdirectory(third_party/protobuf/cmake)
   include_directories(SYSTEM third_party/protobuf/src)
 endif(UNIX)
 
@@ -188,24 +200,31 @@
   else(${PROTOBUF_FOUND})
     set(LIBBLOATY_LIBS ${LIBBLOATY_LIBS} libprotoc)
   endif(${PROTOBUF_FOUND})
-  if(${RE2_FOUND})
-    set(LIBBLOATY_LIBS ${LIBBLOATY_LIBS} ${RE2_LIBRARIES})
-  else(${RE2_FOUND})
-    set(LIBBLOATY_LIBS ${LIBBLOATY_LIBS} re2)
-  endif(${RE2_FOUND})
+  if(BLOATY_ENABLE_RE2)
+    if(${RE2_FOUND})
+      set(LIBBLOATY_LIBS ${LIBBLOATY_LIBS} ${RE2_LIBRARIES})
+    else(${RE2_FOUND})
+      set(LIBBLOATY_LIBS ${LIBBLOATY_LIBS} re2)
+    endif(${RE2_FOUND})
+  endif(BLOATY_ENABLE_RE2)
   if(${CAPSTONE_FOUND})
     set(LIBBLOATY_LIBS ${LIBBLOATY_LIBS} ${CAPSTONE_LIBRARIES})
   else(${CAPSTONE_FOUND})
     set(LIBBLOATY_LIBS ${LIBBLOATY_LIBS} capstone-static)
   endif(${CAPSTONE_FOUND})
 else(UNIX)
-    set(LIBBLOATY_LIBS libbloaty libprotoc re2 capstone-static)
+  set(LIBBLOATY_LIBS libbloaty libprotoc capstone-static)
+  if(BLOATY_ENABLE_RE2)
+    set(LIBBLOATY_LIBS ${LIBBLOATY_LIBS} re2)
+  endif(BLOATY_ENABLE_RE2)
 endif(UNIX)
 
 if(UNIX)
-  if(${RE2_FOUND})
-    link_directories(${RE2_LIBRARY_DIRS})
-  endif(${RE2_FOUND})
+  if(BLOATY_ENABLE_RE2)
+    if(${RE2_FOUND})
+      link_directories(${RE2_LIBRARY_DIRS})
+    endif(${RE2_FOUND})
+  endif(BLOATY_ENABLE_RE2)
   if(${CAPSTONE_FOUND})
     link_directories(${CAPSTONE_LIBRARY_DIRS})
   endif(${CAPSTONE_FOUND})
diff --git a/src/bloaty.cc b/src/bloaty.cc
index 791f8a2..30607a2 100644
--- a/src/bloaty.cc
+++ b/src/bloaty.cc
@@ -45,11 +45,11 @@
 #include "absl/strings/substitute.h"
 #include "google/protobuf/io/zero_copy_stream_impl.h"
 #include "google/protobuf/text_format.h"
-#include "re2/re2.h"
 
 #include "bloaty.h"
 #include "bloaty.pb.h"
 #include "demangle.h"
+#include "re.h"
 
 using absl::string_view;
 
@@ -274,8 +274,8 @@
 // NameMunger //////////////////////////////////////////////////////////////////
 
 void NameMunger::AddRegex(const std::string& regex, const std::string& replacement) {
-  auto re2 = absl::make_unique<RE2>(regex);
-  regexes_.push_back(std::make_pair(std::move(re2), replacement));
+  auto reg = absl::make_unique<ReImpl>(regex);
+  regexes_.push_back(std::make_pair(std::move(reg), replacement));
 }
 
 std::string NameMunger::Munge(string_view name) const {
@@ -283,7 +283,7 @@
   std::string ret(name);
 
   for (const auto& pair : regexes_) {
-    if (RE2::Extract(name_str, *pair.first, pair.second, &ret)) {
+    if (ReImpl::Extract(name_str, *pair.first, pair.second, &ret)) {
       return ret;
     }
   }
@@ -350,7 +350,7 @@
     CreateRows(row, base, options, true);
   }
 
-  void SetFilterRegex(const RE2* regex) {
+  void SetFilterRegex(const ReImpl* regex) {
     filter_regex_ = regex;
   }
 
@@ -393,7 +393,7 @@
   int64_t filtered_vm_total_ = 0;
   int64_t filtered_file_total_ = 0;
 
-  const RE2* filter_regex_ = nullptr;
+  const ReImpl* filter_regex_ = nullptr;
 
   // Putting Rollup by value seems to work on some compilers/libs but not
   // others.
@@ -419,7 +419,7 @@
       bool any_matched = false;
 
       for (const auto& name : names) {
-        if (RE2::PartialMatch(name, *filter_regex_)) {
+        if (ReImpl::PartialMatch(name, *filter_regex_)) {
           any_matched = true;
           break;
         }
@@ -1685,9 +1685,9 @@
   std::vector<std::thread> threads(num_threads);
   ThreadSafeIterIndex index(filenames.size());
 
-  std::unique_ptr<RE2> regex = nullptr;
+  std::unique_ptr<ReImpl> regex = nullptr;
   if (options_.has_source_filter()) {
-    regex = absl::make_unique<RE2>(options_.source_filter());
+    regex = absl::make_unique<ReImpl>(options_.source_filter());
   }
 
   for (int i = 0; i < num_threads; i++) {
@@ -2137,7 +2137,7 @@
   }
 
   if (options.has_source_filter()) {
-    RE2 re(options.source_filter());
+    ReImpl re(options.source_filter());
     if (!re.ok()) {
       THROW("invalid regex for source_filter");
     }
diff --git a/src/bloaty.h b/src/bloaty.h
index 90101ab..bf90945 100644
--- a/src/bloaty.h
+++ b/src/bloaty.h
@@ -34,10 +34,10 @@
 #include "absl/strings/string_view.h"
 #include "absl/strings/strip.h"
 #include "capstone/capstone.h"
-#include "re2/re2.h"
 
 #include "bloaty.pb.h"
 #include "range_map.h"
+#include "re.h"
 
 #define BLOATY_DISALLOW_COPY_AND_ASSIGN(class_name) \
   class_name(const class_name&) = delete; \
@@ -262,14 +262,13 @@
   // Adds a regex that will be applied to all names.  All regexes will be
   // applied in sequence.
   void AddRegex(const std::string& regex, const std::string& replacement);
-
   std::string Munge(absl::string_view name) const;
 
   bool IsEmpty() const { return regexes_.empty(); }
 
  private:
   BLOATY_DISALLOW_COPY_AND_ASSIGN(NameMunger);
-  std::vector<std::pair<std::unique_ptr<RE2>, std::string>> regexes_;
+  std::vector<std::pair<std::unique_ptr<ReImpl>, std::string>> regexes_;
 };
 
 typedef std::map<absl::string_view, std::pair<uint64_t, uint64_t>> SymbolTable;
diff --git a/src/disassemble.cc b/src/disassemble.cc
index 3de593c..d48cac4 100644
--- a/src/disassemble.cc
+++ b/src/disassemble.cc
@@ -21,6 +21,7 @@
 #include "absl/strings/string_view.h"
 #include "absl/strings/substitute.h"
 #include "capstone/capstone.h"
+#include "re.h"
 
 static void Throw(const char *str, int line) {
   throw bloaty::Error(str, __FILE__, line);
@@ -186,20 +187,20 @@
 
     if (info.arch == CS_ARCH_X86) {
       if (in->id == X86_INS_LEA) {
-        RE2::GlobalReplace(&op_str, "\\w?word ptr ", "");
+        ReImpl::GlobalReplace(&op_str, "\\w?word ptr ", "");
       } else if (in->id == X86_INS_NOP) {
         op_str.clear();
       } else {
         // qword ptr => QWORD
-        while (RE2::PartialMatch(op_str, "(\\w?word) ptr", &match)) {
+        while (ReImpl::PartialMatch(op_str, "(\\w?word) ptr", &match)) {
           std::string upper_match = match;
           absl::AsciiStrToUpper(&upper_match);
-          RE2::Replace(&op_str, match + " ptr", upper_match);
+          ReImpl::Replace(&op_str, match + " ptr", upper_match);
         }
       }
     }
 
-    RE2::GlobalReplace(&op_str, " ", "");
+    ReImpl::GlobalReplace(&op_str, " ", "");
 
     auto iter = local_labels.find(in->address);
     if (iter != local_labels.end()) {
diff --git a/src/dwarf.cc b/src/dwarf.cc
index 85a136e..9ca0d4c 100644
--- a/src/dwarf.cc
+++ b/src/dwarf.cc
@@ -33,7 +33,6 @@
 #include "bloaty.h"
 #include "bloaty.pb.h"
 #include "dwarf_constants.h"
-#include "re2/re2.h"
 
 using namespace dwarf2reader;
 using absl::string_view;
diff --git a/src/elf.cc b/src/elf.cc
index 05afc6d..1f9efa5 100644
--- a/src/elf.cc
+++ b/src/elf.cc
@@ -19,7 +19,6 @@
 #include "absl/strings/escaping.h"
 #include "absl/strings/string_view.h"
 #include "absl/strings/substitute.h"
-#include "re2/re2.h"
 #include "third_party/freebsd_elf/elf.h"
 #include "bloaty.h"
 
diff --git a/src/macho.cc b/src/macho.cc
index 0ff52da..64a5250 100644
--- a/src/macho.cc
+++ b/src/macho.cc
@@ -15,7 +15,6 @@
 #include <iostream>
 #include "string.h"
 #include "bloaty.h"
-#include "re2/re2.h"
 
 #include <cassert>
 
diff --git a/src/re.h b/src/re.h
new file mode 100644
index 0000000..d990767
--- /dev/null
+++ b/src/re.h
@@ -0,0 +1,92 @@
+// Copyright 2020 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef BLOATY_RE_H_
+#define BLOATY_RE_H_
+
+#include <string>
+
+#ifdef USE_RE2
+#include "re2/re2.h"
+#endif
+
+#include "absl/base/attributes.h"
+#include "bloaty.h"
+
+namespace bloaty {
+
+#ifdef USE_RE2
+class ReImpl {
+ public:
+  ReImpl(const char* pattern) : re2_(pattern){};
+  ReImpl(const std::string& pattern) : re2_(pattern){};
+  bool ok() { return re2_.ok(); }
+
+  static bool Extract(std::string text, const ReImpl& re, std::string rewrite,
+                      std::string* out) {
+    return RE2::Extract(text, re.re2_, rewrite, out);
+  }
+  template <typename... A>
+  static bool PartialMatch(const std::string& text, const ReImpl& re,
+                           A&&... a) {
+    return RE2::PartialMatch(text, re.re2_, a...);
+  }
+
+  static int GlobalReplace(std::string* str, const ReImpl& re,
+                           std::string rewrite) {
+    return RE2::GlobalReplace(str, re.re2_, rewrite);
+  }
+  static bool Replace(std::string* str, const ReImpl& re, std::string rewrite) {
+    return RE2::Replace(str, re.re2_, rewrite);
+  }
+
+ private:
+  RE2 re2_;
+};
+#else
+}
+
+ABSL_ATTRIBUTE_NORETURN
+static void _abort() { throw "No support for regular expressions"; }
+
+namespace bloaty {
+class ReImpl {
+ public:
+  ReImpl(const char*) { _abort(); }
+  ReImpl(const std::string&) { _abort(); }
+  bool ok() { _abort(); }
+
+  ABSL_ATTRIBUTE_NORETURN
+  static bool Extract(std::string, const ReImpl&, std::string, std::string*) {
+    _abort();
+  }
+  template <typename... A>
+  ABSL_ATTRIBUTE_NORETURN static bool PartialMatch(const std::string&,
+                                                   const ReImpl&, A&&...) {
+    _abort();
+  }
+  ABSL_ATTRIBUTE_NORETURN
+  static int GlobalReplace(std::string*, const ReImpl&, std::string) {
+    _abort();
+  }
+  ABSL_ATTRIBUTE_NORETURN
+  static bool Replace(std::string*, const ReImpl&, std::string) { _abort(); }
+
+ private:
+};
+#endif
+
+}  // namespace bloaty
+
+#endif  // BLOATY_RE_H_