Partially resolve google/benchmark#17 by fixing regular expression leak.

This adds a unit test to validate the wrapper without running the entirety of
benchmark_test.
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 6c5857c..5c6a390 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,6 +1,8 @@
 set(SOURCE_FILES "benchmark.cc" "colorprint.cc" "commandlineflags.cc" "sleep.cc" "sysinfo.cc" "walltime.cc")
+set(RE_FILES "re.cc")
 
-add_library(benchmark STATIC ${SOURCE_FILES})
+add_library(benchmark_re STATIC ${RE_FILES})
+add_library(benchmark STATIC ${SOURCE_FILES} ${RE_FILES})
 
 # Install target (will install the library to specified CMAKE_INSTALL_PREFIX variable)
 install(
diff --git a/src/benchmark.cc b/src/benchmark.cc
index 7e1357f..e3055a7 100644
--- a/src/benchmark.cc
+++ b/src/benchmark.cc
@@ -17,6 +17,7 @@
 #include "colorprint.h"
 #include "commandlineflags.h"
 #include "mutex_lock.h"
+#include "re.h"
 #include "sleep.h"
 #include "stat.h"
 #include "sysinfo.h"
@@ -27,12 +28,6 @@
 #include <semaphore.h>
 #include <string.h>
 
-#if defined OS_FREEBSD
-#include <gnuregex.h>
-#else
-#include <regex.h>
-#endif
-
 #include <algorithm>
 #include <atomic>
 #include <iostream>
@@ -745,14 +740,10 @@
 void Benchmark::FindBenchmarks(const std::string& spec,
                                std::vector<Instance>* benchmarks) {
   // Make regular expression out of command-line flag
-  regex_t re;
-  int ec = regcomp(&re, spec.c_str(), REG_EXTENDED | REG_NOSUB);
-  if (ec != 0) {
-    size_t needed = regerror(ec, &re, NULL, 0);
-    char* errbuf = new char[needed];
-    regerror(ec, &re, errbuf, needed);
-    std::cerr << "Could not compile benchmark re: " << errbuf << "\n";
-    delete[] errbuf;
+  Regex re;
+  std::string re_error;
+  if (!re.Init(spec, &re_error)) {
+    std::cerr << "Could not compile benchmark re: " << re_error << std::endl;
     return;
   }
 
@@ -762,7 +753,7 @@
     if (family == nullptr) continue;  // Family was deleted
 
     // Match against filter.
-    if (regexec(&re, family->name_.c_str(), 0, NULL, 0) != 0) {
+    if (!re.Match(family->name_)) {
 #ifdef DEBUG
       std::cout << "Skipping " << family->name_ << "\n";
 #endif
diff --git a/src/re.cc b/src/re.cc
new file mode 100644
index 0000000..e51e2b6
--- /dev/null
+++ b/src/re.cc
@@ -0,0 +1,59 @@
+// Copyright 2014 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.
+
+#include <benchmark/macros.h>
+#include "re.h"
+
+namespace benchmark {
+
+Regex::Regex() : init_(false) { }
+
+bool Regex::Init(const std::string& spec, std::string* error) {
+  int ec = regcomp(&re_, spec.c_str(), REG_EXTENDED | REG_NOSUB);
+  if (ec != 0) {
+    if (error) {
+      size_t needed = regerror(ec, &re_, NULL, 0);
+      char* errbuf = new char[needed];
+      regerror(ec, &re_, errbuf, needed);
+
+      // regerror returns the number of bytes necessary to null terminate
+      // the string, so we move that when assigning to error.
+      CHECK_NE(needed, 0);
+      error->assign(errbuf, needed - 1);
+
+      delete[] errbuf;
+    }
+
+    return false;
+  }
+
+  init_ = true;
+  return true;
+}
+
+Regex::~Regex() {
+  if (init_) {
+    regfree(&re_);
+  }
+}
+
+bool Regex::Match(const std::string& str) {
+  if (!init_) {
+    return false;
+  }
+
+  return regexec(&re_, str.c_str(), 0, NULL, 0) == 0;
+}
+
+}  // end namespace benchmark
diff --git a/src/re.h b/src/re.h
new file mode 100644
index 0000000..b179bb2
--- /dev/null
+++ b/src/re.h
@@ -0,0 +1,50 @@
+// Copyright 2014 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 BENCHMARK_RE_H_
+#define BENCHMARK_RE_H_
+
+#if defined OS_FREEBSD
+#include <gnuregex.h>
+#else
+#include <regex.h>
+#endif
+#include <string>
+
+namespace benchmark {
+
+// A wrapper around the POSIX regular expression API that provides automatic
+// cleanup
+class Regex {
+ public:
+  Regex();
+  ~Regex();
+
+  // Compile a regular expression matcher from spec.  Returns true on success.
+  //
+  // On failure (and if error is not NULL), error is populated with a human
+  // readable error message if an error occurs.
+  bool Init(const std::string& spec, std::string* error);
+
+  // Returns whether str matches the compiled regular expression.
+  bool Match(const std::string& str);
+ private:
+  bool init_;
+  // Underlying regular expression object
+  regex_t re_;
+};
+
+}  // end namespace benchmark
+
+#endif  // BENCHMARK_RE_H_
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index f725365..2999c2c 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,3 +1,8 @@
 # Demonstration executable
 add_executable(benchmark_test benchmark_test.cc)
 target_link_libraries(benchmark_test benchmark ${CMAKE_THREAD_LIBS_INIT})
+
+# Test harness for regex wrapper
+add_executable(re_test ${RE_FILES} "re_test.cc")
+target_link_libraries(re_test benchmark_re ${CMAKE_THREAD_LIBS_INIT} gtest gtest_main)
+add_test(regex re_test)
diff --git a/test/re_test.cc b/test/re_test.cc
new file mode 100644
index 0000000..c5ff9aa
--- /dev/null
+++ b/test/re_test.cc
@@ -0,0 +1,39 @@
+// Copyright 2014 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.
+
+#include <gtest/gtest.h>
+#include "re.h"
+
+TEST(Regex, RegexSimple) {
+    benchmark::Regex re;
+    EXPECT_TRUE(re.Init("a+", NULL));
+
+    EXPECT_FALSE(re.Match(""));
+    EXPECT_TRUE(re.Match("a"));
+    EXPECT_TRUE(re.Match("aa"));
+    EXPECT_FALSE(re.Match("b"));
+}
+
+TEST(Regex, InvalidNoErrorMessage) {
+    benchmark::Regex re;
+    EXPECT_FALSE(re.Init("[", NULL));
+}
+
+TEST(Regex, Invalid) {
+    std::string error;
+    benchmark::Regex re;
+    EXPECT_FALSE(re.Init("[", &error));
+
+    EXPECT_NE("", error);
+}