Ports libpcrecpp to pcre2

Ports the c++ wrapper around pcre to pcre2 and doing
some modifications on the way.

- Lifts the limitation of matching arguments that
  could be passed to the members of pcrecpp::RE without
  changing the API.

- The newline mode can no longer be specified as an option
  flag. Instead it must be passed to the pattern compiler using
  a compile context. Therefore, a member was added to REOptions,
  holding the newline mode.

- The PCRE_EXTRA option has no equivalent in pcre2 and was
  removed.

Merged-In: I0bd5da97128fda25b8b2014c94bed9422540dd67
Bug: 24091652
Change-Id: I0bd5da97128fda25b8b2014c94bed9422540dd67
diff --git a/Android.bp b/Android.bp
index 00fb54a..2c0ab27 100644
--- a/Android.bp
+++ b/Android.bp
@@ -50,12 +50,17 @@
 
 // === libpcrecpp targets ===
 
-//cc_library_shared {
-//    name: "libpcrecpp",
-//    cflags: libpcre_cflags,
-//    local_include_dirs: ["dist"],
-//
-//    srcs: libpcrecpp_src_files,
-//    shared_libs: ["libpcre"],
-//    export_include_dirs: ["."],
-//}
+cc_library_shared {
+    name: "libpcrecpp",
+    local_include_dirs: ["pcrecpp/include"],
+    shared_libs: ["libpcre2"],
+    export_include_dirs: [
+        "pcrecpp/include",
+        "include",
+    ],
+    srcs: [
+	"pcrecpp/pcrecpp.cc",
+        "pcrecpp/pcre_scanner.cc",
+        "pcrecpp/pcre_stringpiece.cc",
+    ],
+}
diff --git a/pcrecpp/include/pcre_scanner.h b/pcrecpp/include/pcre_scanner.h
index 5617e45..b2bfabe 100644
--- a/pcrecpp/include/pcre_scanner.h
+++ b/pcrecpp/include/pcre_scanner.h
@@ -53,7 +53,7 @@
 
 namespace pcrecpp {
 
-class PCRECPP_EXP_DEFN Scanner {
+class Scanner {
  public:
   Scanner();
   explicit Scanner(const std::string& input);
@@ -79,12 +79,13 @@
   //       parsed and stored into the arguments.
   // If it returns true, it skips over the matched input and any
   // following input that matches the "skip" regular expression.
-  bool Consume(const RE& re,
-               const Arg& arg0 = RE::no_arg,
-               const Arg& arg1 = RE::no_arg,
-               const Arg& arg2 = RE::no_arg
-               // TODO: Allow more arguments?
-               );
+  template<typename ... ARGS>
+  bool Consume(const RE& re, ARGS && ... args) {
+    const bool result = re.Consume(&input_, args...);
+    if (result && should_skip_)
+      ConsumeSkip();
+    return result;
+  }
 
   // Set the "skip" regular expression.  If after consuming some data,
   // a prefix of the input matches this RE, it is automatically
diff --git a/pcrecpp/include/pcre_stringpiece.h b/pcrecpp/include/pcre_stringpiece.h
index cc3dc42..51b9812 100644
--- a/pcrecpp/include/pcre_stringpiece.h
+++ b/pcrecpp/include/pcre_stringpiece.h
@@ -50,7 +50,7 @@
 #include <bits/type_traits.h>
 #endif
 
-#include <pcre.h>
+#include <pcre2.h>
 
 using std::memcmp;
 using std::strlen;
@@ -58,7 +58,7 @@
 
 namespace pcrecpp {
 
-class PCRECPP_EXP_DEFN StringPiece {
+class StringPiece {
  private:
   const char*   ptr_;
   int           length_;
@@ -174,7 +174,7 @@
 #endif
 
 // allow StringPiece to be logged
-PCRECPP_EXP_DECL std::ostream& operator<<(std::ostream& o,
+extern std::ostream& operator<<(std::ostream& o,
                                           const pcrecpp::StringPiece& piece);
 
 #endif /* _PCRE_STRINGPIECE_H */
diff --git a/pcrecpp/include/pcrecpp.h b/pcrecpp/include/pcrecpp.h
index 3e594b0..0c216b2 100644
--- a/pcrecpp/include/pcrecpp.h
+++ b/pcrecpp/include/pcrecpp.h
@@ -331,11 +331,12 @@
 
 
 #include <string>
-#include <pcre.h>
+#include <pcre2.h>
 #include <pcrecpparg.h>   // defines the Arg class
 // This isn't technically needed here, but we include it
 // anyway so folks who include pcrecpp.h don't have to.
 #include <pcre_stringpiece.h>
+#include <memory>
 
 namespace pcrecpp {
 
@@ -346,16 +347,23 @@
 #define PCRE_IS_SET(o)  \
         (all_options_ & o) == o
 
+typedef std::shared_ptr<pcre2_match_data> pcre2_match_data_ptr;
+
 /***** Compiling regular expressions: the RE class *****/
 
 // RE_Options allow you to set options to be passed along to pcre,
 // along with other options we put on top of pcre.
 // Only 9 modifiers, plus match_limit and match_limit_recursion,
 // are supported now.
-class PCRECPP_EXP_DEFN RE_Options {
+class RE_Options {
  public:
   // constructor
-  RE_Options() : match_limit_(0), match_limit_recursion_(0), all_options_(0) {}
+  RE_Options()
+      : newline_mode_(0),
+        match_limit_(0),
+        match_limit_recursion_(0),
+        all_options_(0) {
+  }
 
   // alternative constructor.
   // To facilitate transfer of legacy code from C programs
@@ -365,8 +373,12 @@
   // But new code is better off doing
   //    RE(pattern,
   //      RE_Options().set_caseless(true).set_multiline(true)).PartialMatch(str);
-  RE_Options(int option_flags) : match_limit_(0), match_limit_recursion_(0),
-                                 all_options_(option_flags) {}
+  RE_Options(int option_flags)
+      : newline_mode_(0),
+        match_limit_(0),
+        match_limit_recursion_(0),
+        all_options_(option_flags) {
+  }
   // we're fine with the default destructor, copy constructor, etc.
 
   // accessors and mutators
@@ -383,66 +395,74 @@
   }
 
   bool caseless() const {
-    return PCRE_IS_SET(PCRE_CASELESS);
+    return PCRE_IS_SET(PCRE2_CASELESS);
   }
   RE_Options &set_caseless(bool x) {
-    PCRE_SET_OR_CLEAR(x, PCRE_CASELESS);
+    PCRE_SET_OR_CLEAR(x, PCRE2_CASELESS);
   }
 
   bool multiline() const {
-    return PCRE_IS_SET(PCRE_MULTILINE);
+    return PCRE_IS_SET(PCRE2_MULTILINE);
   }
   RE_Options &set_multiline(bool x) {
-    PCRE_SET_OR_CLEAR(x, PCRE_MULTILINE);
+    PCRE_SET_OR_CLEAR(x, PCRE2_MULTILINE);
+  }
+
+  int newline_mode() const {
+    if(newline_mode_)
+      return newline_mode_;
+    else {
+      // if newline_mode_ is 0 return the global configuration default
+      int value;
+      pcre2_config_8(PCRE2_CONFIG_NEWLINE, &value);
+      return value;
+    }
+  }
+  RE_Options & set_newline_mode(int newline_mode) {
+    newline_mode_ = newline_mode;
+    return *this;
   }
 
   bool dotall() const {
-    return PCRE_IS_SET(PCRE_DOTALL);
+    return PCRE_IS_SET(PCRE2_DOTALL);
   }
   RE_Options &set_dotall(bool x) {
-    PCRE_SET_OR_CLEAR(x, PCRE_DOTALL);
+    PCRE_SET_OR_CLEAR(x, PCRE2_DOTALL);
   }
 
   bool extended() const {
-    return PCRE_IS_SET(PCRE_EXTENDED);
+    return PCRE_IS_SET(PCRE2_EXTENDED);
   }
   RE_Options &set_extended(bool x) {
-    PCRE_SET_OR_CLEAR(x, PCRE_EXTENDED);
+    PCRE_SET_OR_CLEAR(x, PCRE2_EXTENDED);
   }
 
   bool dollar_endonly() const {
-    return PCRE_IS_SET(PCRE_DOLLAR_ENDONLY);
+    return PCRE_IS_SET(PCRE2_DOLLAR_ENDONLY);
   }
   RE_Options &set_dollar_endonly(bool x) {
-    PCRE_SET_OR_CLEAR(x, PCRE_DOLLAR_ENDONLY);
-  }
-
-  bool extra() const {
-    return PCRE_IS_SET(PCRE_EXTRA);
-  }
-  RE_Options &set_extra(bool x) {
-    PCRE_SET_OR_CLEAR(x, PCRE_EXTRA);
+    PCRE_SET_OR_CLEAR(x, PCRE2_DOLLAR_ENDONLY);
   }
 
   bool ungreedy() const {
-    return PCRE_IS_SET(PCRE_UNGREEDY);
+    return PCRE_IS_SET(PCRE2_UNGREEDY);
   }
   RE_Options &set_ungreedy(bool x) {
-    PCRE_SET_OR_CLEAR(x, PCRE_UNGREEDY);
+    PCRE_SET_OR_CLEAR(x, PCRE2_UNGREEDY);
   }
 
-  bool utf8() const {
-    return PCRE_IS_SET(PCRE_UTF8);
+  bool utf() const {
+    return PCRE_IS_SET(PCRE2_UTF);
   }
-  RE_Options &set_utf8(bool x) {
-    PCRE_SET_OR_CLEAR(x, PCRE_UTF8);
+  RE_Options &set_utf(bool x) {
+    PCRE_SET_OR_CLEAR(x, PCRE2_UTF);
   }
 
   bool no_auto_capture() const {
-    return PCRE_IS_SET(PCRE_NO_AUTO_CAPTURE);
+    return PCRE_IS_SET(PCRE2_NO_AUTO_CAPTURE);
   }
   RE_Options &set_no_auto_capture(bool x) {
-    PCRE_SET_OR_CLEAR(x, PCRE_NO_AUTO_CAPTURE);
+    PCRE_SET_OR_CLEAR(x, PCRE2_NO_AUTO_CAPTURE);
   }
 
   RE_Options &set_all_options(int opt) {
@@ -456,14 +476,15 @@
   // TODO: add other pcre flags
 
  private:
+  int newline_mode_;
   int match_limit_;
   int match_limit_recursion_;
   int all_options_;
 };
 
 // These functions return some common RE_Options
-static inline RE_Options UTF8() {
-  return RE_Options().set_utf8(true);
+static inline RE_Options UTF() {
+  return RE_Options().set_utf(true);
 }
 
 static inline RE_Options CASELESS() {
@@ -484,7 +505,7 @@
 // Interface for regular expression matching.  Also corresponds to a
 // pre-compiled regular expression.  An "RE" object is safe for
 // concurrent use by multiple threads.
-class PCRECPP_EXP_DEFN RE {
+class RE {
  public:
   // We provide implicit conversions from strings so that users can
   // pass in a string or a "const char*" wherever an "RE" is expected.
@@ -525,84 +546,63 @@
 
   // If RE could not be created properly, returns an error string.
   // Else returns the empty string.
-  const string& error() const { return *error_; }
+  const string& error() const { return error_; }
 
   /***** The useful part: the matching interface *****/
 
   // This is provided so one can do pattern.ReplaceAll() just as
   // easily as ReplaceAll(pattern-text, ....)
 
-  bool FullMatch(const StringPiece& text,
-                 const Arg& ptr1 = no_arg,
-                 const Arg& ptr2 = no_arg,
-                 const Arg& ptr3 = no_arg,
-                 const Arg& ptr4 = no_arg,
-                 const Arg& ptr5 = no_arg,
-                 const Arg& ptr6 = no_arg,
-                 const Arg& ptr7 = no_arg,
-                 const Arg& ptr8 = no_arg,
-                 const Arg& ptr9 = no_arg,
-                 const Arg& ptr10 = no_arg,
-                 const Arg& ptr11 = no_arg,
-                 const Arg& ptr12 = no_arg,
-                 const Arg& ptr13 = no_arg,
-                 const Arg& ptr14 = no_arg,
-                 const Arg& ptr15 = no_arg,
-                 const Arg& ptr16 = no_arg) const;
+  template<typename ... ARGS>
+  bool FullMatch(const StringPiece & text, ARGS && ...a) const {
+    // create an array with the size of the number of arguments given
+    Arg args[Args<ARGS...>::count()];
+    // initialize the array with the arguments given
+    Args<ARGS...>::arrayify(args, a...);
 
-  bool PartialMatch(const StringPiece& text,
-                    const Arg& ptr1 = no_arg,
-                    const Arg& ptr2 = no_arg,
-                    const Arg& ptr3 = no_arg,
-                    const Arg& ptr4 = no_arg,
-                    const Arg& ptr5 = no_arg,
-                    const Arg& ptr6 = no_arg,
-                    const Arg& ptr7 = no_arg,
-                    const Arg& ptr8 = no_arg,
-                    const Arg& ptr9 = no_arg,
-                    const Arg& ptr10 = no_arg,
-                    const Arg& ptr11 = no_arg,
-                    const Arg& ptr12 = no_arg,
-                    const Arg& ptr13 = no_arg,
-                    const Arg& ptr14 = no_arg,
-                    const Arg& ptr15 = no_arg,
-                    const Arg& ptr16 = no_arg) const;
+    return DoMatchImpl(text, ANCHOR_BOTH, NULL, args, Args<ARGS...>::count());
+  }
 
-  bool Consume(StringPiece* input,
-               const Arg& ptr1 = no_arg,
-               const Arg& ptr2 = no_arg,
-               const Arg& ptr3 = no_arg,
-               const Arg& ptr4 = no_arg,
-               const Arg& ptr5 = no_arg,
-               const Arg& ptr6 = no_arg,
-               const Arg& ptr7 = no_arg,
-               const Arg& ptr8 = no_arg,
-               const Arg& ptr9 = no_arg,
-               const Arg& ptr10 = no_arg,
-               const Arg& ptr11 = no_arg,
-               const Arg& ptr12 = no_arg,
-               const Arg& ptr13 = no_arg,
-               const Arg& ptr14 = no_arg,
-               const Arg& ptr15 = no_arg,
-               const Arg& ptr16 = no_arg) const;
+  template<typename ... ARGS>
+  bool PartialMatch(const StringPiece& text, ARGS && ...a) const {
+    // create an array with the size of the number of arguments given
+    Arg args[Args<ARGS...>::count()];
+    // initialize the array with the arguments given
+    Args<ARGS...>::arrayify(args, a...);
 
-  bool FindAndConsume(StringPiece* input,
-                      const Arg& ptr1 = no_arg,
-                      const Arg& ptr2 = no_arg,
-                      const Arg& ptr3 = no_arg,
-                      const Arg& ptr4 = no_arg,
-                      const Arg& ptr5 = no_arg,
-                      const Arg& ptr6 = no_arg,
-                      const Arg& ptr7 = no_arg,
-                      const Arg& ptr8 = no_arg,
-                      const Arg& ptr9 = no_arg,
-                      const Arg& ptr10 = no_arg,
-                      const Arg& ptr11 = no_arg,
-                      const Arg& ptr12 = no_arg,
-                      const Arg& ptr13 = no_arg,
-                      const Arg& ptr14 = no_arg,
-                      const Arg& ptr15 = no_arg,
-                      const Arg& ptr16 = no_arg) const;
+    return DoMatchImpl(text, UNANCHORED, NULL, args, Args<ARGS...>::count());
+  }
+
+  template<typename ... ARGS>
+  bool Consume(StringPiece* input, ARGS && ...a) const {
+    // create an array with the size of the number of arguments given
+    Arg args[Args<ARGS...>::count()];
+    // initialize the array with the arguments given
+    Args<ARGS...>::arrayify(args, a...);
+
+    int consumed;
+    if (DoMatchImpl(*input, ANCHOR_START, &consumed, args,
+                    Args<ARGS...>::count())) {
+      input->remove_prefix(consumed);
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  template<typename ... ARGS>
+  bool FindAndConsume(StringPiece* input, ARGS && ...a) const {
+    Arg args[Args<ARGS...>::count()];
+    Args<ARGS...>::arrayify(args, a...);
+    int consumed;
+    if (DoMatchImpl(*input, UNANCHORED, &consumed, args,
+                    Args<ARGS...>::count())) {
+      input->remove_prefix(consumed);
+      return true;
+    } else {
+      return false;
+    }
+  }
 
   bool Replace(const StringPiece& rewrite,
                string *str) const;
@@ -640,21 +640,12 @@
   bool DoMatch(const StringPiece& text,
                Anchor anchor,
                int* consumed,
-               const Arg* const* args, int n) const;
+               Arg const argsp[], int n) const;
 
   // Return the number of capturing subpatterns, or -1 if the
   // regexp wasn't valid on construction.
   int NumberOfCapturingGroups() const;
 
-  // The default value for an argument, to indicate the end of the argument
-  // list. This must be used only in optional argument defaults. It should NOT
-  // be passed explicitly. Some people have tried to use it like this:
-  //
-  //   FullMatch(x, y, &z, no_arg, &w);
-  //
-  // This is a mistake, and will not work.
-  static Arg no_arg;
-
  private:
 
   void Init(const string& pattern, const RE_Options* options);
@@ -675,34 +666,30 @@
                int startpos,
                Anchor anchor,
                bool empty_ok,
-               int *vec,
-               int vecsize) const;
+               pcre2_match_data_ptr & match_data) const;
 
   // Append the "rewrite" string, with backslash subsitutions from "text"
   // and "vec", to string "out".
   bool Rewrite(string *out,
                const StringPiece& rewrite,
                const StringPiece& text,
-               int *vec,
-               int veclen) const;
+               pcre2_match_data_ptr const & match_data) const;
 
   // internal implementation for DoMatch
   bool DoMatchImpl(const StringPiece& text,
                    Anchor anchor,
                    int* consumed,
-                   const Arg* const args[],
-                   int n,
-                   int* vec,
-                   int vecsize) const;
+                   const Arg args[],
+                   int n) const;
 
   // Compile the regexp for the specified anchoring mode
-  pcre* Compile(Anchor anchor);
+  pcre2_code * Compile(Anchor anchor);
 
   string        pattern_;
   RE_Options    options_;
-  pcre*         re_full_;       // For full matches
-  pcre*         re_partial_;    // For partial matches
-  const string* error_;         // Error indicator (or points to empty string)
+  pcre2_code*   re_full_;       // For full matches
+  pcre2_code*   re_partial_;    // For partial matches
+  string        error_;         // Error indicator
 };
 
 }   // namespace pcrecpp
diff --git a/pcrecpp/include/pcrecpparg.h b/pcrecpp/include/pcrecpparg.h
index b4f9c3f..0a1713f 100644
--- a/pcrecpp/include/pcrecpparg.h
+++ b/pcrecpp/include/pcrecpparg.h
@@ -35,7 +35,7 @@
 #include <stdlib.h>    // for NULL
 #include <string>
 
-#include <pcre.h>
+#include <pcre2.h>
 
 namespace pcrecpp {
 
@@ -54,7 +54,7 @@
   }
 };
 
-class PCRECPP_EXP_DEFN Arg {
+class Arg {
  public:
   // Empty constructor so we can declare arrays of Arg
   Arg();
@@ -168,6 +168,40 @@
 #undef PCRE_SET_OR_CLEAR
 #undef MAKE_INTEGER_PARSER
 
+template<typename ARG>
+inline Arg wrap_arg(ARG && any) {
+  return Arg(any);
+}
+
+inline Arg const & wrap_arg(Arg const & arg) {
+  return arg;
+}
+
+template<typename ... ARGS>
+struct Args;
+
+template<typename HEAD, typename ... TAIL>
+struct Args<HEAD, TAIL...> {
+  typedef Args<TAIL...> next;
+  constexpr static unsigned count() {
+    return 1 + next::count();
+  }
+  template<typename _HEAD, typename ... _TAIL>
+  inline static void arrayify(Arg * ptr, _HEAD && head, _TAIL && ... tail) {
+    *ptr++ = wrap_arg(head);
+    next::arrayify(ptr, tail...);
+  }
+};
+
+template<>
+struct Args<> {
+  constexpr static unsigned count() {
+    return 0;
+  }
+  inline static void arrayify(Arg *) {
+  }
+};
+
 }   // namespace pcrecpp
 
 
diff --git a/pcrecpp/pcre_scanner.cc b/pcrecpp/pcre_scanner.cc
index 6be2be6..2887d6b 100644
--- a/pcrecpp/pcre_scanner.cc
+++ b/pcrecpp/pcre_scanner.cc
@@ -29,10 +29,6 @@
 //
 // Author: Sanjay Ghemawat
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <vector>
 #include <assert.h>
 
@@ -130,15 +126,6 @@
 }
 
 
-bool Scanner::Consume(const RE& re,
-                      const Arg& arg0,
-                      const Arg& arg1,
-                      const Arg& arg2) {
-  const bool result = re.Consume(&input_, arg0, arg1, arg2);
-  if (result && should_skip_) ConsumeSkip();
-  return result;
-}
-
 // helper function to consume *skip_ and honour save_comments_
 void Scanner::ConsumeSkip() {
   const char* start_data = input_.data();
diff --git a/pcrecpp/pcre_stringpiece.cc b/pcrecpp/pcre_stringpiece.cc
index 67c0f1f..599e466 100644
--- a/pcrecpp/pcre_stringpiece.cc
+++ b/pcrecpp/pcre_stringpiece.cc
@@ -30,10 +30,6 @@
 // Author: wilsonh@google.com (Wilson Hsieh)
 //
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <iostream>
 #include "pcrecpp_internal.h"
 #include "pcre_stringpiece.h"
diff --git a/pcrecpp/pcrecpp.cc b/pcrecpp/pcrecpp.cc
index c595cbc..2c37c44 100644
--- a/pcrecpp/pcrecpp.cc
+++ b/pcrecpp/pcrecpp.cc
@@ -29,10 +29,6 @@
 //
 // Author: Sanjay Ghemawat
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <stdlib.h>
 #include <stdio.h>
 #include <ctype.h>
@@ -44,39 +40,13 @@
 #include <algorithm>
 
 #include "pcrecpp_internal.h"
-#include "pcre.h"
+#include "pcre2.h"
 #include "pcrecpp.h"
 #include "pcre_stringpiece.h"
 
 
 namespace pcrecpp {
 
-// Maximum number of args we can set
-static const int kMaxArgs = 16;
-static const int kVecSize = (1 + kMaxArgs) * 3;  // results + PCRE workspace
-
-// Special object that stands-in for no argument
-Arg RE::no_arg((void*)NULL);
-
-// This is for ABI compatibility with old versions of pcre (pre-7.6),
-// which defined a global no_arg variable instead of putting it in the
-// RE class.  This works on GCC >= 3, at least.  It definitely works
-// for ELF, but may not for other object formats (Mach-O, for
-// instance, does not support aliases.)  We could probably have a more
-// inclusive test if we ever needed it.  (Note that not only the
-// __attribute__ syntax, but also __USER_LABEL_PREFIX__, are
-// gnu-specific.)
-#if defined(__GNUC__) && __GNUC__ >= 3 && defined(__ELF__)
-# define ULP_AS_STRING(x)            ULP_AS_STRING_INTERNAL(x)
-# define ULP_AS_STRING_INTERNAL(x)   #x
-# define USER_LABEL_PREFIX_STR       ULP_AS_STRING(__USER_LABEL_PREFIX__)
-extern Arg no_arg
-  __attribute__((alias(USER_LABEL_PREFIX_STR "_ZN7pcrecpp2RE6no_argE")));
-#endif
-
-// If a regular expression has no error, its error_ field points here
-static const string empty_string;
-
 // If the user doesn't ask for any options, we just use this one
 static RE_Options default_options;
 
@@ -87,7 +57,7 @@
   } else {
     options_ = *options;
   }
-  error_ = &empty_string;
+  error_ = "";
   re_full_ = NULL;
   re_partial_ = NULL;
 
@@ -98,9 +68,9 @@
 }
 
 void RE::Cleanup() {
-  if (re_full_ != NULL)         (*pcre_free)(re_full_);
-  if (re_partial_ != NULL)      (*pcre_free)(re_partial_);
-  if (error_ != &empty_string)  delete error_;
+  if (re_full_ != NULL)         pcre2_code_free(re_full_);
+  if (re_partial_ != NULL)      pcre2_code_free(re_partial_);
+  error_ = "";
 }
 
 
@@ -108,11 +78,38 @@
   Cleanup();
 }
 
+static void format_pcre_error(int error, string & str) {
+  PCRE2_UCHAR8 buffer[256];
+  auto rc = pcre2_get_error_message(error, buffer, 256);
+  str.assign(reinterpret_cast<string::value_type*>(buffer));
+  if (rc == PCRE2_ERROR_NOMEMORY) {
+    str.append("...");
+  }
+}
 
-pcre* RE::Compile(Anchor anchor) {
+pcre2_code* RE::Compile(Anchor anchor) {
   // First, convert RE_Options into pcre options
   int pcre_options = 0;
   pcre_options = options_.all_options();
+  typedef std::unique_ptr<pcre2_compile_context,
+      decltype(pcre2_compile_context_free)*> compile_context_ptr;
+  compile_context_ptr compile_context(NULL, pcre2_compile_context_free);
+
+  // As of pcre2 the newline mode must be passed through the compile context.
+  // So we only need one if the newline mode is actually set.
+  if (options_.newline_mode()) {
+    compile_context = compile_context_ptr(pcre2_compile_context_create(NULL),
+    pcre2_compile_context_free);
+    if (!compile_context) {
+      error_ = "Unable to allocate memory for pcre2_compile_congext";
+      return NULL;
+    }
+    if (pcre2_set_newline(compile_context.get(),
+                          options_.newline_mode()) == PCRE2_ERROR_BADDATA) {
+      error_ = "REOptions: bad newline mode given";
+      return NULL;
+    }
+  }
 
   // Special treatment for anchoring.  This is needed because at
   // runtime pcre only provides an option for anchoring at the
@@ -126,265 +123,71 @@
   //    ANCHOR_BOTH     Tack a "\z" to the end of the original pattern
   //                    and use a pcre anchored match.
 
-  const char* compile_error;
-  int eoffset;
-  pcre* re;
+  int compile_error;
+  PCRE2_SIZE eoffset;
+  pcre2_code* re;
   if (anchor != ANCHOR_BOTH) {
-    re = pcre_compile(pattern_.c_str(), pcre_options,
-                      &compile_error, &eoffset, NULL);
+    re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>(pattern_.c_str()),
+                       pattern_.length(), pcre_options, &compile_error,
+                       &eoffset, compile_context.get());
   } else {
     // Tack a '\z' at the end of RE.  Parenthesize it first so that
     // the '\z' applies to all top-level alternatives in the regexp.
     string wrapped = "(?:";  // A non-counting grouping operator
     wrapped += pattern_;
     wrapped += ")\\z";
-    re = pcre_compile(wrapped.c_str(), pcre_options,
-                      &compile_error, &eoffset, NULL);
+    re = pcre2_compile(reinterpret_cast<PCRE2_SPTR>(wrapped.c_str()),
+                       wrapped.length(), pcre_options, &compile_error, &eoffset,
+                       compile_context.get());
   }
   if (re == NULL) {
-    if (error_ == &empty_string) error_ = new string(compile_error);
+    format_pcre_error(compile_error, error_);
   }
   return re;
 }
 
 /***** Matching interfaces *****/
 
-bool RE::FullMatch(const StringPiece& text,
-                   const Arg& ptr1,
-                   const Arg& ptr2,
-                   const Arg& ptr3,
-                   const Arg& ptr4,
-                   const Arg& ptr5,
-                   const Arg& ptr6,
-                   const Arg& ptr7,
-                   const Arg& ptr8,
-                   const Arg& ptr9,
-                   const Arg& ptr10,
-                   const Arg& ptr11,
-                   const Arg& ptr12,
-                   const Arg& ptr13,
-                   const Arg& ptr14,
-                   const Arg& ptr15,
-                   const Arg& ptr16) const {
-  const Arg* args[kMaxArgs];
-  int n = 0;
-  if (&ptr1  == &no_arg) goto done; args[n++] = &ptr1;
-  if (&ptr2  == &no_arg) goto done; args[n++] = &ptr2;
-  if (&ptr3  == &no_arg) goto done; args[n++] = &ptr3;
-  if (&ptr4  == &no_arg) goto done; args[n++] = &ptr4;
-  if (&ptr5  == &no_arg) goto done; args[n++] = &ptr5;
-  if (&ptr6  == &no_arg) goto done; args[n++] = &ptr6;
-  if (&ptr7  == &no_arg) goto done; args[n++] = &ptr7;
-  if (&ptr8  == &no_arg) goto done; args[n++] = &ptr8;
-  if (&ptr9  == &no_arg) goto done; args[n++] = &ptr9;
-  if (&ptr10 == &no_arg) goto done; args[n++] = &ptr10;
-  if (&ptr11 == &no_arg) goto done; args[n++] = &ptr11;
-  if (&ptr12 == &no_arg) goto done; args[n++] = &ptr12;
-  if (&ptr13 == &no_arg) goto done; args[n++] = &ptr13;
-  if (&ptr14 == &no_arg) goto done; args[n++] = &ptr14;
-  if (&ptr15 == &no_arg) goto done; args[n++] = &ptr15;
-  if (&ptr16 == &no_arg) goto done; args[n++] = &ptr16;
- done:
-
-  int consumed;
-  int vec[kVecSize];
-  return DoMatchImpl(text, ANCHOR_BOTH, &consumed, args, n, vec, kVecSize);
-}
-
-bool RE::PartialMatch(const StringPiece& text,
-                      const Arg& ptr1,
-                      const Arg& ptr2,
-                      const Arg& ptr3,
-                      const Arg& ptr4,
-                      const Arg& ptr5,
-                      const Arg& ptr6,
-                      const Arg& ptr7,
-                      const Arg& ptr8,
-                      const Arg& ptr9,
-                      const Arg& ptr10,
-                      const Arg& ptr11,
-                      const Arg& ptr12,
-                      const Arg& ptr13,
-                      const Arg& ptr14,
-                      const Arg& ptr15,
-                      const Arg& ptr16) const {
-  const Arg* args[kMaxArgs];
-  int n = 0;
-  if (&ptr1  == &no_arg) goto done; args[n++] = &ptr1;
-  if (&ptr2  == &no_arg) goto done; args[n++] = &ptr2;
-  if (&ptr3  == &no_arg) goto done; args[n++] = &ptr3;
-  if (&ptr4  == &no_arg) goto done; args[n++] = &ptr4;
-  if (&ptr5  == &no_arg) goto done; args[n++] = &ptr5;
-  if (&ptr6  == &no_arg) goto done; args[n++] = &ptr6;
-  if (&ptr7  == &no_arg) goto done; args[n++] = &ptr7;
-  if (&ptr8  == &no_arg) goto done; args[n++] = &ptr8;
-  if (&ptr9  == &no_arg) goto done; args[n++] = &ptr9;
-  if (&ptr10 == &no_arg) goto done; args[n++] = &ptr10;
-  if (&ptr11 == &no_arg) goto done; args[n++] = &ptr11;
-  if (&ptr12 == &no_arg) goto done; args[n++] = &ptr12;
-  if (&ptr13 == &no_arg) goto done; args[n++] = &ptr13;
-  if (&ptr14 == &no_arg) goto done; args[n++] = &ptr14;
-  if (&ptr15 == &no_arg) goto done; args[n++] = &ptr15;
-  if (&ptr16 == &no_arg) goto done; args[n++] = &ptr16;
- done:
-
-  int consumed;
-  int vec[kVecSize];
-  return DoMatchImpl(text, UNANCHORED, &consumed, args, n, vec, kVecSize);
-}
-
-bool RE::Consume(StringPiece* input,
-                 const Arg& ptr1,
-                 const Arg& ptr2,
-                 const Arg& ptr3,
-                 const Arg& ptr4,
-                 const Arg& ptr5,
-                 const Arg& ptr6,
-                 const Arg& ptr7,
-                 const Arg& ptr8,
-                 const Arg& ptr9,
-                 const Arg& ptr10,
-                 const Arg& ptr11,
-                 const Arg& ptr12,
-                 const Arg& ptr13,
-                 const Arg& ptr14,
-                 const Arg& ptr15,
-                 const Arg& ptr16) const {
-  const Arg* args[kMaxArgs];
-  int n = 0;
-  if (&ptr1  == &no_arg) goto done; args[n++] = &ptr1;
-  if (&ptr2  == &no_arg) goto done; args[n++] = &ptr2;
-  if (&ptr3  == &no_arg) goto done; args[n++] = &ptr3;
-  if (&ptr4  == &no_arg) goto done; args[n++] = &ptr4;
-  if (&ptr5  == &no_arg) goto done; args[n++] = &ptr5;
-  if (&ptr6  == &no_arg) goto done; args[n++] = &ptr6;
-  if (&ptr7  == &no_arg) goto done; args[n++] = &ptr7;
-  if (&ptr8  == &no_arg) goto done; args[n++] = &ptr8;
-  if (&ptr9  == &no_arg) goto done; args[n++] = &ptr9;
-  if (&ptr10 == &no_arg) goto done; args[n++] = &ptr10;
-  if (&ptr11 == &no_arg) goto done; args[n++] = &ptr11;
-  if (&ptr12 == &no_arg) goto done; args[n++] = &ptr12;
-  if (&ptr13 == &no_arg) goto done; args[n++] = &ptr13;
-  if (&ptr14 == &no_arg) goto done; args[n++] = &ptr14;
-  if (&ptr15 == &no_arg) goto done; args[n++] = &ptr15;
-  if (&ptr16 == &no_arg) goto done; args[n++] = &ptr16;
- done:
-
-  int consumed;
-  int vec[kVecSize];
-  if (DoMatchImpl(*input, ANCHOR_START, &consumed,
-                  args, n, vec, kVecSize)) {
-    input->remove_prefix(consumed);
-    return true;
-  } else {
-    return false;
-  }
-}
-
-bool RE::FindAndConsume(StringPiece* input,
-                        const Arg& ptr1,
-                        const Arg& ptr2,
-                        const Arg& ptr3,
-                        const Arg& ptr4,
-                        const Arg& ptr5,
-                        const Arg& ptr6,
-                        const Arg& ptr7,
-                        const Arg& ptr8,
-                        const Arg& ptr9,
-                        const Arg& ptr10,
-                        const Arg& ptr11,
-                        const Arg& ptr12,
-                        const Arg& ptr13,
-                        const Arg& ptr14,
-                        const Arg& ptr15,
-                        const Arg& ptr16) const {
-  const Arg* args[kMaxArgs];
-  int n = 0;
-  if (&ptr1  == &no_arg) goto done; args[n++] = &ptr1;
-  if (&ptr2  == &no_arg) goto done; args[n++] = &ptr2;
-  if (&ptr3  == &no_arg) goto done; args[n++] = &ptr3;
-  if (&ptr4  == &no_arg) goto done; args[n++] = &ptr4;
-  if (&ptr5  == &no_arg) goto done; args[n++] = &ptr5;
-  if (&ptr6  == &no_arg) goto done; args[n++] = &ptr6;
-  if (&ptr7  == &no_arg) goto done; args[n++] = &ptr7;
-  if (&ptr8  == &no_arg) goto done; args[n++] = &ptr8;
-  if (&ptr9  == &no_arg) goto done; args[n++] = &ptr9;
-  if (&ptr10 == &no_arg) goto done; args[n++] = &ptr10;
-  if (&ptr11 == &no_arg) goto done; args[n++] = &ptr11;
-  if (&ptr12 == &no_arg) goto done; args[n++] = &ptr12;
-  if (&ptr13 == &no_arg) goto done; args[n++] = &ptr13;
-  if (&ptr14 == &no_arg) goto done; args[n++] = &ptr14;
-  if (&ptr15 == &no_arg) goto done; args[n++] = &ptr15;
-  if (&ptr16 == &no_arg) goto done; args[n++] = &ptr16;
- done:
-
-  int consumed;
-  int vec[kVecSize];
-  if (DoMatchImpl(*input, UNANCHORED, &consumed,
-                  args, n, vec, kVecSize)) {
-    input->remove_prefix(consumed);
-    return true;
-  } else {
-    return false;
-  }
-}
-
 bool RE::Replace(const StringPiece& rewrite,
                  string *str) const {
-  int vec[kVecSize];
-  int matches = TryMatch(*str, 0, UNANCHORED, true, vec, kVecSize);
+  pcre2_match_data_ptr match_data;
+  int matches = TryMatch(*str, 0, UNANCHORED, true, match_data);
   if (matches == 0)
     return false;
 
   string s;
-  if (!Rewrite(&s, rewrite, *str, vec, matches))
+  if (!Rewrite(&s, rewrite, *str, match_data))
     return false;
 
+  auto vec = pcre2_get_ovector_pointer(match_data.get());
+
   assert(vec[0] >= 0);
   assert(vec[1] >= 0);
   str->replace(vec[0], vec[1] - vec[0], s);
   return true;
 }
 
-// Returns PCRE_NEWLINE_CRLF, PCRE_NEWLINE_CR, or PCRE_NEWLINE_LF.
-// Note that PCRE_NEWLINE_CRLF is defined to be P_N_CR | P_N_LF.
-// Modified by PH to add PCRE_NEWLINE_ANY and PCRE_NEWLINE_ANYCRLF.
-
-static int NewlineMode(int pcre_options) {
-  // TODO: if we can make it threadsafe, cache this var
-  int newline_mode = 0;
-  /* if (newline_mode) return newline_mode; */  // do this once it's cached
-  if (pcre_options & (PCRE_NEWLINE_CRLF|PCRE_NEWLINE_CR|PCRE_NEWLINE_LF|
-                      PCRE_NEWLINE_ANY|PCRE_NEWLINE_ANYCRLF)) {
-    newline_mode = (pcre_options &
-                    (PCRE_NEWLINE_CRLF|PCRE_NEWLINE_CR|PCRE_NEWLINE_LF|
-                     PCRE_NEWLINE_ANY|PCRE_NEWLINE_ANYCRLF));
-  } else {
-    int newline;
-    pcre_config(PCRE_CONFIG_NEWLINE, &newline);
-    if (newline == 10)
-      newline_mode = PCRE_NEWLINE_LF;
-    else if (newline == 13)
-      newline_mode = PCRE_NEWLINE_CR;
-    else if (newline == 3338)
-      newline_mode = PCRE_NEWLINE_CRLF;
-    else if (newline == -1)
-      newline_mode = PCRE_NEWLINE_ANY;
-    else if (newline == -2)
-      newline_mode = PCRE_NEWLINE_ANYCRLF;
-    else
-      assert(NULL == "Unexpected return value from pcre_config(NEWLINE)");
+static bool is_multi_char_newline_mode(int value) {
+  switch (value) {
+    case PCRE2_NEWLINE_CR:
+    case PCRE2_NEWLINE_LF:
+      return false;
+    case PCRE2_NEWLINE_CRLF:
+    case PCRE2_NEWLINE_ANY:
+    case PCRE2_NEWLINE_ANYCRLF:
+      return true;
+    default:
+      return false;
   }
-  return newline_mode;
 }
 
 int RE::GlobalReplace(const StringPiece& rewrite,
                       string *str) const {
   int count = 0;
-  int vec[kVecSize];
   string out;
   int start = 0;
   bool last_match_was_empty_string = false;
+  pcre2_match_data_ptr match_data;
 
   while (start <= static_cast<int>(str->length())) {
     // If the previous match was for the empty string, we shouldn't
@@ -399,19 +202,17 @@
     //    perl -le '$_ = "aa"; s/b*|aa/@/g; print'
     int matches;
     if (last_match_was_empty_string) {
-      matches = TryMatch(*str, start, ANCHOR_START, false, vec, kVecSize);
+      matches = TryMatch(*str, start, ANCHOR_START, false, match_data);
       if (matches <= 0) {
         int matchend = start + 1;     // advance one character.
         // If the current char is CR and we're in CRLF mode, skip LF too.
-        // Note it's better to call pcre_fullinfo() than to examine
-        // all_options(), since options_ could have changed bewteen
+        // Note it's better to call pcre2_pattern_info() than to examine
+        // all_options(), since options_ could have changed between
         // compile-time and now, but this is simpler and safe enough.
         // Modified by PH to add ANY and ANYCRLF.
         if (matchend < static_cast<int>(str->length()) &&
             (*str)[start] == '\r' && (*str)[matchend] == '\n' &&
-            (NewlineMode(options_.all_options()) == PCRE_NEWLINE_CRLF ||
-             NewlineMode(options_.all_options()) == PCRE_NEWLINE_ANY ||
-             NewlineMode(options_.all_options()) == PCRE_NEWLINE_ANYCRLF)) {
+            is_multi_char_newline_mode(options_.newline_mode())) {
           matchend++;
         }
         // We also need to advance more than one char if we're in utf8 mode.
@@ -429,15 +230,16 @@
         continue;
       }
     } else {
-      matches = TryMatch(*str, start, UNANCHORED, true, vec, kVecSize);
+      matches = TryMatch(*str, start, UNANCHORED, true, match_data);
       if (matches <= 0)
         break;
     }
+    auto vec = pcre2_get_ovector_pointer(match_data.get());
     int matchstart = vec[0], matchend = vec[1];
     assert(matchstart >= start);
     assert(matchend >= matchstart);
     out.append(*str, start, matchstart - start);
-    Rewrite(&out, rewrite, *str, vec, matches);
+    Rewrite(&out, rewrite, *str, match_data);
     start = matchend;
     count++;
     last_match_was_empty_string = (matchstart == matchend);
@@ -455,12 +257,12 @@
 bool RE::Extract(const StringPiece& rewrite,
                  const StringPiece& text,
                  string *out) const {
-  int vec[kVecSize];
-  int matches = TryMatch(text, 0, UNANCHORED, true, vec, kVecSize);
+  pcre2_match_data_ptr match_data;
+  int matches = TryMatch(text, 0, UNANCHORED, true, match_data);
   if (matches == 0)
     return false;
   out->erase();
-  return Rewrite(out, rewrite, text, vec, matches);
+  return Rewrite(out, rewrite, text, match_data);
 }
 
 /*static*/ string RE::QuoteMeta(const StringPiece& unquoted) {
@@ -498,79 +300,84 @@
 }
 
 /***** Actual matching and rewriting code *****/
-
 int RE::TryMatch(const StringPiece& text,
                  int startpos,
                  Anchor anchor,
                  bool empty_ok,
-                 int *vec,
-                 int vecsize) const {
-  pcre* re = (anchor == ANCHOR_BOTH) ? re_full_ : re_partial_;
+                 pcre2_match_data_ptr & match_data) const {
+  typedef std::unique_ptr<pcre2_match_context,
+      decltype(pcre2_match_context_free)*> match_context_ptr;
+
+  pcre2_code* re = (anchor == ANCHOR_BOTH) ? re_full_ : re_partial_;
   if (re == NULL) {
     //fprintf(stderr, "Matching against invalid re: %s\n", error_->c_str());
     return 0;
   }
+  match_context_ptr match_context = match_context_ptr(
+      pcre2_match_context_create(NULL),
+      pcre2_match_context_free);
+  if (!match_context)
+    return 0;
 
-  pcre_extra extra = { 0, 0, 0, 0, 0, 0, 0, 0 };
   if (options_.match_limit() > 0) {
-    extra.flags |= PCRE_EXTRA_MATCH_LIMIT;
-    extra.match_limit = options_.match_limit();
+    pcre2_set_match_limit(match_context.get(), options_.match_limit());
   }
   if (options_.match_limit_recursion() > 0) {
-    extra.flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
-    extra.match_limit_recursion = options_.match_limit_recursion();
+    pcre2_set_recursion_limit(match_context.get(),
+                              options_.match_limit_recursion());
+  }
+
+  match_data = pcre2_match_data_ptr(
+      pcre2_match_data_create_from_pattern(re, NULL),
+      pcre2_match_data_free);
+  if (!match_data) {
+    return 0;
   }
 
   // int options = 0;
   // Changed by PH as a result of bugzilla #1288
-  int options = (options_.all_options() & PCRE_NO_UTF8_CHECK);
+  int options = (options_.all_options() & PCRE2_NO_UTF_CHECK);
 
   if (anchor != UNANCHORED)
-    options |= PCRE_ANCHORED;
+    options |= PCRE2_ANCHORED;
   if (!empty_ok)
-    options |= PCRE_NOTEMPTY;
+    options |= PCRE2_NOTEMPTY;
 
-  int rc = pcre_exec(re,              // The regular expression object
-                     &extra,
-                     (text.data() == NULL) ? "" : text.data(),
-                     text.size(),
-                     startpos,
-                     options,
-                     vec,
-                     vecsize);
+  int rc = pcre2_match(
+      re, reinterpret_cast<PCRE2_SPTR>((text.empty()) ? "" : text.data()),
+      text.size(), startpos, options, match_data.get(), match_context.get());
 
   // Handle errors
-  if (rc == PCRE_ERROR_NOMATCH) {
+  if (rc == PCRE2_ERROR_NOMATCH) {
+    return 0;
+  }
+  if (rc == PCRE2_ERROR_PARTIAL) {
+    // not sure what to do with partial yet
     return 0;
   } else if (rc < 0) {
-    //fprintf(stderr, "Unexpected return code: %d when matching '%s'\n",
-    //        re, pattern_.c_str());
+    // For any other error condition also return 0.
     return 0;
-  } else if (rc == 0) {
-    // pcre_exec() returns 0 as a special case when the number of
-    // capturing subpatterns exceeds the size of the vector.
-    // When this happens, there is a match and the output vector
-    // is filled, but we miss out on the positions of the extra subpatterns.
-    rc = vecsize / 2;
   }
 
-  return rc;
+  return rc; // return number of matches found
 }
 
 bool RE::DoMatchImpl(const StringPiece& text,
                      Anchor anchor,
                      int* consumed,
-                     const Arg* const* args,
-                     int n,
-                     int* vec,
-                     int vecsize) const {
-  assert((1 + n) * 3 <= vecsize);  // results + PCRE workspace
-  int matches = TryMatch(text, 0, anchor, true, vec, vecsize);
+                     const Arg* args,
+                     int n) const {
+  pcre2_match_data_ptr match_data;
+  int matches = TryMatch(text, 0, anchor, true, match_data);
   assert(matches >= 0);  // TryMatch never returns negatives
   if (matches == 0)
     return false;
 
-  *consumed = vec[1];
+  auto vec = pcre2_get_ovector_pointer(match_data.get());
+
+  // allow for NULL
+  if (consumed != NULL)
+    *consumed = vec[1];
 
   if (n == 0 || args == NULL) {
     // We are not interested in results
@@ -588,7 +395,7 @@
   for (int i = 0; i < n; i++) {
     const int start = vec[2*(i+1)];
     const int limit = vec[2*(i+1)+1];
-    if (!args[i]->Parse(text.data() + start, limit-start)) {
+    if (!args[i].Parse(text.data() + start, limit - start)) {
       // TODO: Should we indicate what the error was?
       return false;
     }
@@ -600,27 +407,25 @@
 bool RE::DoMatch(const StringPiece& text,
                  Anchor anchor,
                  int* consumed,
-                 const Arg* const args[],
+                 Arg const args[],
                  int n) const {
   assert(n >= 0);
-  size_t const vecsize = (1 + n) * 3;  // results + PCRE workspace
-                                       // (as for kVecSize)
-  int space[21];   // use stack allocation for small vecsize (common case)
-  int* vec = vecsize <= 21 ? space : new int[vecsize];
-  bool retval = DoMatchImpl(text, anchor, consumed, args, n, vec, (int)vecsize);
-  if (vec != space) delete [] vec;
+  bool retval = DoMatchImpl(text, anchor, consumed, args, n);
   return retval;
 }
 
 bool RE::Rewrite(string *out, const StringPiece &rewrite,
-                 const StringPiece &text, int *vec, int veclen) const {
+                 const StringPiece &text,
+                 pcre2_match_data_ptr const & match_data) const {
+  auto veclen = pcre2_get_ovector_count(match_data.get());
+  auto vec = pcre2_get_ovector_pointer(match_data.get());
   for (const char *s = rewrite.data(), *end = s + rewrite.size();
        s < end; s++) {
     int c = *s;
     if (c == '\\') {
       c = *++s;
       if (isdigit(c)) {
-        int n = (c - '0');
+        decltype(veclen) n = (c - '0');
         if (n >= veclen) {
           //fprintf(stderr, requested group %d in regexp %.*s\n",
           //        n, rewrite.size(), rewrite.data());
@@ -649,10 +454,8 @@
   if (re_partial_ == NULL) return -1;
 
   int result;
-  int pcre_retval = pcre_fullinfo(re_partial_,  // The regular expression object
-                                  NULL,         // We did not study the pattern
-                                  PCRE_INFO_CAPTURECOUNT,
-                                  &result);
+  int pcre_retval = pcre2_pattern_info(re_partial_, PCRE2_INFO_CAPTURECOUNT,
+                                       &result);
   assert(pcre_retval == 0);
   return result;
 }
diff --git a/pcrecpp/pcrecpp_unittest.cc b/pcrecpp/pcrecpp_unittest.cc
index 92cae8f..67f2398 100644
--- a/pcrecpp/pcrecpp_unittest.cc
+++ b/pcrecpp/pcrecpp_unittest.cc
@@ -333,7 +333,8 @@
 #endif
 
   for (const ReplaceTest *t = tests; t->original != NULL; ++t) {
-    RE re(t->regexp, RE_Options(PCRE_NEWLINE_CRLF).set_utf8(support_utf8));
+    RE re(t->regexp, RE_Options().set_newline_mode(PCRE2_NEWLINE_CRLF)
+                                 .set_utf(support_utf8));
     assert(re.error().empty());
     string one(t->original);
     CHECK(re.Replace(t->rewrite, &one));
@@ -346,14 +347,16 @@
 
   // One final test: test \r\n replacement when we're not in CRLF mode
   {
-    RE re("b*", RE_Options(PCRE_NEWLINE_CR).set_utf8(support_utf8));
+    RE re("b*", RE_Options().set_newline_mode(PCRE2_NEWLINE_CR)
+                            .set_utf(support_utf8));
     assert(re.error().empty());
     string all("aa\r\naa\r\n");
     CHECK_EQ(re.GlobalReplace("bb", &all), 9);
     CHECK_EQ(all, string("bbabbabb\rbb\nbbabbabb\rbb\nbb"));
   }
   {
-    RE re("b*", RE_Options(PCRE_NEWLINE_LF).set_utf8(support_utf8));
+    RE re("b*", RE_Options().set_newline_mode(PCRE2_NEWLINE_LF)
+                            .set_utf(support_utf8));
     assert(re.error().empty());
     string all("aa\r\naa\r\n");
     CHECK_EQ(re.GlobalReplace("bb", &all), 9);
@@ -662,17 +665,6 @@
   TestOneOption("DOLLAR_ENDONLY 2",    "world$", str, options2.set_dollar_endonly(true), false, false);
 }
 
-static void Test_EXTRA() {
-  RE_Options options;
-  const char *str = "HELLO";
-
-  options.set_extra(true);
-  TestOneOption("EXTRA 1", "\\HELL\\O", str, options, true, false );
-  TestOneOption("EXTRA 2", "\\HELL\\O", str, RE_Options().set_extra(true), true, false );
-  options.set_extra(false);
-  TestOneOption("no EXTRA", "\\HELL\\O", str, options, true );
-}
-
 static void Test_EXTENDED() {
   RE_Options options;
   RE_Options options2;
@@ -738,18 +730,18 @@
 static void Test_all_options() {
   const char *str = "HELLO\n" "cruel\n" "world";
   RE_Options options;
-  options.set_all_options(PCRE_CASELESS | PCRE_DOTALL);
+  options.set_all_options(PCRE2_CASELESS | PCRE2_DOTALL);
 
   TestOneOption("all_options (CASELESS|DOTALL)", "^hello.*WORLD", str , options, false);
   options.set_all_options(0);
   TestOneOption("all_options (0)", "^hello.*WORLD", str , options, false, false);
-  options.set_all_options(PCRE_MULTILINE | PCRE_EXTENDED);
+  options.set_all_options(PCRE2_MULTILINE | PCRE2_EXTENDED);
 
   TestOneOption("all_options (MULTILINE|EXTENDED)", " ^ c r u e l $ ", str, options, false);
   TestOneOption("all_options (MULTILINE|EXTENDED) with constructor",
                   " ^ c r u e l $ ",
                   str,
-                  RE_Options(PCRE_MULTILINE | PCRE_EXTENDED),
+                  RE_Options(PCRE2_MULTILINE | PCRE2_EXTENDED),
                   false);
 
   TestOneOption("all_options (MULTILINE|EXTENDED) with concatenation",
@@ -774,7 +766,6 @@
   Test_EXTENDED();
   Test_NO_AUTO_CAPTURE();
   Test_UNGREEDY();
-  Test_EXTRA();
   Test_all_options();
 }