Only five simple flags are allowed so far, and not all of them are actually used in any code. They are: ~anchored / PCRE_ANCHORED - implicit ^...$ around regexp ~caseless / PCRE_CASELESS - fold upper and lower case ~dotall / PCRE_DOTALL - ‘.’ matches anything ~extended / PCRE_EXTENDED - extended regular expressions ~multiline / PCRE_MULTILINE - ^ and $ match lines within the subject string --- common/mlpcre/PCRE.ml | 2 +- common/mlpcre/PCRE.mli | 10 ++++++++-- common/mlpcre/pcre-c.c | 41 ++++++++++++++++++++++++++++++++++++++--- common/mlpcre/pcre_tests.ml | 22 +++++++++++++++------- 4 files changed, 62 insertions(+), 13 deletions(-) diff --git a/common/mlpcre/PCRE.ml b/common/mlpcre/PCRE.ml index 0eb7eb2ec..753e247e4 100644 --- a/common/mlpcre/PCRE.ml +++ b/common/mlpcre/PCRE.ml @@ -22,7 +22,7 @@ exception Error of string * int type regexp -external compile : string -> regexp = "guestfs_int_pcre_compile" +external compile : ?anchored:bool -> ?caseless:bool -> ?dotall:bool -> ?extended:bool -> ?multiline:bool -> string -> regexp = "guestfs_int_pcre_compile_byte" "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" diff --git a/common/mlpcre/PCRE.mli b/common/mlpcre/PCRE.mli index 634cc600c..fcf6fd25e 100644 --- a/common/mlpcre/PCRE.mli +++ b/common/mlpcre/PCRE.mli @@ -53,8 +53,14 @@ exception Error of string * int type regexp (** The type of a compiled regular expression. *) -val compile : string -> regexp -(** Compile a regular expression. This can raise {!Error}. *) +val compile : ?anchored:bool -> ?caseless:bool -> ?dotall:bool -> ?extended:bool -> ?multiline:bool -> string -> regexp +(** Compile a regular expression. This can raise {!Error}. + + The flags [?anchored], [?caseless], [?dotall], [?extended], + [?multiline] + correspond to the [pcre_compile] flags [PCRE_ANCHORED] etc. + See pcreapi(3) for details of what they do. + All flags default to false. *) val matches : regexp -> string -> bool (** Test whether the regular expression matches the string. This diff --git a/common/mlpcre/pcre-c.c b/common/mlpcre/pcre-c.c index 15775dad0..6dc30087d 100644 --- a/common/mlpcre/pcre-c.c +++ b/common/mlpcre/pcre-c.c @@ -112,22 +112,57 @@ Val_regexp (pcre *re) CAMLreturn (rv); } +static int +is_Some_true (value v) +{ + return + v != Val_int (0) /* !None */ && + Bool_val (Field (v, 0)) /* Some true */; +} + value -guestfs_int_pcre_compile (value pattv) +guestfs_int_pcre_compile (value anchoredv, value caselessv, value dotallv, + value extendedv, value multilinev, + value pattv) { - CAMLparam1 (pattv); + CAMLparam5 (anchoredv, caselessv, dotallv, extendedv, multilinev); + CAMLxparam1 (pattv); + int options = 0; pcre *re; int errcode = 0; const char *err; int offset; - re = pcre_compile2 (String_val (pattv), 0, &errcode, &err, &offset, NULL); + /* Flag parameters are all ‘bool option’, defaulting to false. */ + if (is_Some_true (anchoredv)) + options |= PCRE_ANCHORED; + if (is_Some_true (caselessv)) + options |= PCRE_CASELESS; + if (is_Some_true (dotallv)) + options |= PCRE_DOTALL; + if (is_Some_true (extendedv)) + options |= PCRE_EXTENDED; + if (is_Some_true (multilinev)) + options |= PCRE_MULTILINE; + + re = pcre_compile2 (String_val (pattv), options, + &errcode, &err, &offset, NULL); if (re == NULL) raise_pcre_error (err, errcode); CAMLreturn (Val_regexp (re)); } +/* OCaml calls C functions from bytecode a bit differently when they + * have more than 5 parameters. + */ +value +guestfs_int_pcre_compile_byte (value *argv, int argn) +{ + return guestfs_int_pcre_compile (argv[0], argv[1], argv[2], argv[3], argv[4], + argv[5]); +} + value guestfs_int_pcre_matches (value rev, value strv) { diff --git a/common/mlpcre/pcre_tests.ml b/common/mlpcre/pcre_tests.ml index b5f712d20..9d42914b9 100644 --- a/common/mlpcre/pcre_tests.ml +++ b/common/mlpcre/pcre_tests.ml @@ -18,9 +18,17 @@ open Printf -let compile patt = - eprintf "PCRE.compile %s\n%!" patt; - PCRE.compile patt +let compile ?(anchored = false) ?(caseless = false) + ?(dotall = false) ?(extended = false) ?(multiline = false) + patt = + eprintf "PCRE.compile%s%s%s%s%s %s\n%!" + (if anchored then " ~anchored:true" else "") + (if caseless then " ~caseless:true" else "") + (if dotall then " ~dotall:true" else "") + (if extended then " ~extended:true" else "") + (if multiline then " ~multiline:true" else "") + patt; + PCRE.compile ~anchored ~caseless ~dotall ~extended ~multiline patt let matches re str = eprintf "PCRE.matches %s ->%!" str; @@ -51,7 +59,7 @@ let () = let re0 = compile "a+b" in let re1 = compile "(a+)b" in let re2 = compile "(a+)(b*)" in - let re3 = compile "[^A-Za-z0-9_]" in + let re3 = compile ~caseless:true "[^a-z0-9_]" in assert (matches re0 "ccaaabbbb" = true); assert (sub 0 = "aaab"); @@ -90,9 +98,9 @@ let () = * patterns, and that could be problematic if PCRE was built * without Unicode support (XXX). *) - assert (replace ~global:true re3 "-" "this is a\xc2\xa3funny.name?" - (* = "this-is-a-funny-name-" if UTF-8 worked *) - = "this-is-a--funny-name-"); + assert (replace ~global:true re3 "-" "this is a\xc2\xa3FUNNY.name?" + (* = "this-is-a-FUNNY-name-" if UTF-8 worked *) + = "this-is-a--FUNNY-name-"); with | Not_found -> failwith "one of the PCRE.sub functions unexpectedly raised Not_found" -- 2.13.2