---
common/mlpcre/PCRE.ml | 3 +--
common/mlpcre/PCRE.mli | 14 ++++++++++++++
common/mlpcre/pcre-c.c | 27 +++++++++++++++++++++++++++
common/mlpcre/pcre_tests.ml | 19 ++++++++++++++++---
4 files changed, 58 insertions(+), 5 deletions(-)
diff --git a/common/mlpcre/PCRE.ml b/common/mlpcre/PCRE.ml
index 94eea4b34..5269d41f8 100644
--- a/common/mlpcre/PCRE.ml
+++ b/common/mlpcre/PCRE.ml
@@ -23,10 +23,9 @@ exception Error of string * int
type regexp
external compile : string -> regexp = "guestfs_int_pcre_compile"
-
external matches : regexp -> string -> bool = "guestfs_int_pcre_matches"
-
external sub : int -> string = "guestfs_int_pcre_sub"
+external subi : int -> int * int = "guestfs_int_pcre_subi"
let () =
Callback.register_exception "PCRE.Error" (Error ("", 0))
diff --git a/common/mlpcre/PCRE.mli b/common/mlpcre/PCRE.mli
index 331a50a9a..02f16d19d 100644
--- a/common/mlpcre/PCRE.mli
+++ b/common/mlpcre/PCRE.mli
@@ -77,3 +77,17 @@ val sub : int -> string
If there was no nth substring then this raises [Not_found].
This can also raise {!Error} for other PCRE-related errors. *)
+
+val subi : int -> int * int
+(** Return the nth substring (capture) matched by the previous call
+ to {!matches} in the current thread.
+
+ This is the same as {!sub} but instead of copying the
+ substring out, it returns the indexes into the original string
+ of the first character of the substring and the first
+ character after the substring.
+
+ (See pcreapi(3) section "How pcre_exec() returns captured substrings"
+ for exact details).
+
+ If there was no nth substring then this raises [Not_found]. *)
diff --git a/common/mlpcre/pcre-c.c b/common/mlpcre/pcre-c.c
index da9b50d34..15775dad0 100644
--- a/common/mlpcre/pcre-c.c
+++ b/common/mlpcre/pcre-c.c
@@ -225,3 +225,30 @@ guestfs_int_pcre_sub (value nv)
memcpy (String_val (strv), str, len);
CAMLreturn (strv);
}
+
+value
+guestfs_int_pcre_subi (value nv)
+{
+ CAMLparam1 (nv);
+ int n = Int_val (nv);
+ CAMLlocal1 (rv);
+ struct last_match *m = gl_tls_get (last_match);
+
+ if (m == NULL)
+ raise_pcre_error ("PCRE.subi called without calling PCRE.matches", 0);
+
+ if (n < 0)
+ caml_invalid_argument ("PCRE.subi: n must be >= 0");
+
+ /* eg if there are 2 captures, m->r == 3, and valid values of n are
+ * 0, 1 or 2.
+ */
+ if (n >= m->r)
+ caml_raise_not_found ();
+
+ rv = caml_alloc (2, 0);
+ Store_field (rv, 0, Val_int (m->vec[n*2]));
+ Store_field (rv, 1, Val_int (m->vec[n*2+1]));
+
+ CAMLreturn (rv);
+}
diff --git a/common/mlpcre/pcre_tests.ml b/common/mlpcre/pcre_tests.ml
index 2b18f462f..316a4348e 100644
--- a/common/mlpcre/pcre_tests.ml
+++ b/common/mlpcre/pcre_tests.ml
@@ -34,6 +34,12 @@ let sub i =
eprintf " %s\n%!" r;
r
+let subi i =
+ eprintf "PCRE.subi %d ->%!" i;
+ let i1, i2 = PCRE.subi i in
+ eprintf " (%d, %d)\n%!" i1 i2;
+ (i1, i2)
+
let () =
try
let re0 = compile "a+b" in
@@ -62,19 +68,26 @@ let () =
assert (matches re2 "ccac" = true);
assert (sub 1 = "a");
assert (sub 2 = "");
- assert (sub 0 = "a")
+ assert (sub 0 = "a");
+ assert (subi 0 = (2, 3));
+ assert (subi 1 = (2, 3));
+ assert (subi 2 = (3, 3))
with
| Not_found ->
failwith "one of the PCRE.sub functions unexpectedly raised Not_found"
| PCRE.Error (msg, code) ->
failwith (sprintf "PCRE error: %s (PCRE error code %d)" msg code)
-(* Run some out of range [sub] calls to ensure an exception is thrown. *)
+(* Run some out of range [sub] and [subi] calls to ensure an exception
+ * is thrown.
+ *)
let () =
let re2 = compile "(a+)(b*)" in
ignore (matches re2 "ccac");
(try ignore (sub 3) with Not_found -> ());
- (try ignore (sub (-1)) with Invalid_argument _ -> ())
+ (try ignore (sub (-1)) with Invalid_argument _ -> ());
+ (try ignore (subi 3) with Not_found -> ());
+ (try ignore (subi (-1)) with Invalid_argument _ -> ())
(* Compile some bad regexps and check that an exception is thrown.
* It would be nice to check the error message is right but
--
2.13.2