Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package ocaml-re for openSUSE:Factory checked in at 2021-09-29 20:18:36 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ocaml-re (Old) and /work/SRC/openSUSE:Factory/.ocaml-re.new.1899 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ocaml-re" Wed Sep 29 20:18:36 2021 rev:6 rq:921280 version:1.10.3 Changes: -------- --- /work/SRC/openSUSE:Factory/ocaml-re/ocaml-re.changes 2021-04-29 01:37:18.354485358 +0200 +++ /work/SRC/openSUSE:Factory/.ocaml-re.new.1899/ocaml-re.changes 2021-09-29 20:19:42.159057048 +0200 @@ -1,0 +2,6 @@ +Sat Sep 11 12:34:56 UTC 2021 - oher...@suse.de + +- Update to version 1.10.3 + see included CHANGES for details + +------------------------------------------------------------------- Old: ---- ocaml-re-1.9.0.tar.xz New: ---- ocaml-re-1.10.3.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ocaml-re.spec ++++++ --- /var/tmp/diff_new_pack.720JSg/_old 2021-09-29 20:19:42.535057594 +0200 +++ /var/tmp/diff_new_pack.720JSg/_new 2021-09-29 20:19:42.539057600 +0200 @@ -25,7 +25,7 @@ %define pkg ocaml-re Name: %{pkg}%{nsuffix} -Version: 1.9.0 +Version: 1.10.3 Release: 0 %{?ocaml_preserve_bytecode} Summary: Pure OCaml regular expressions @@ -34,8 +34,8 @@ URL: https://opam.ocaml.org/packages/re Source0: %{pkg}-%{version}.tar.xz BuildRequires: ocaml -BuildRequires: ocaml-dune -BuildRequires: ocaml-rpm-macros >= 20210121 +BuildRequires: ocaml-dune >= 2.0 +BuildRequires: ocaml-rpm-macros >= 20210911 %if 1 BuildRequires: ocamlfind(seq) BuildRequires: ocamlfind(str) ++++++ _service ++++++ --- /var/tmp/diff_new_pack.720JSg/_old 2021-09-29 20:19:42.579057658 +0200 +++ /var/tmp/diff_new_pack.720JSg/_new 2021-09-29 20:19:42.579057658 +0200 @@ -1,7 +1,7 @@ <services> <service name="tar_scm" mode="disabled"> <param name="filename">ocaml-re</param> - <param name="revision">42c7f8899c9b1a4e011053487a97cf7eab312d5f</param> + <param name="revision">c5d5df80e128c3d7646b7d8b1322012c5fcc35f3</param> <param name="scm">git</param> <param name="submodules">disable</param> <param name="url">https://github.com/ocaml/ocaml-re.git</param> ++++++ ocaml-re-1.9.0.tar.xz -> ocaml-re-1.10.3.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/.gitignore new/ocaml-re-1.10.3/.gitignore --- old/ocaml-re-1.9.0/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/ocaml-re-1.10.3/.gitignore 2021-09-13 21:26:15.000000000 +0200 @@ -0,0 +1,11 @@ +.*.swp +_build/ +*.bak +setup.data +setup.log +setup.exe +*.native +*.byte +*.docdir +.merlin +*.install \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/.vscode/settings.json new/ocaml-re-1.10.3/.vscode/settings.json --- old/ocaml-re-1.9.0/.vscode/settings.json 1970-01-01 01:00:00.000000000 +0100 +++ new/ocaml-re-1.10.3/.vscode/settings.json 2021-09-13 21:26:15.000000000 +0200 @@ -0,0 +1,6 @@ +{ + "ocaml.sandbox": { + "kind": "opam", + "switch": "4.12.0" + } +} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/CHANGES.md new/ocaml-re-1.10.3/CHANGES.md --- old/ocaml-re-1.9.0/CHANGES.md 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/CHANGES.md 2021-09-13 21:26:15.000000000 +0200 @@ -1,3 +1,32 @@ +1.10.3 (13-Sep-2021) +-------------------- + +* Glob: change optional argument `?backslash_escapes` to `?match_backslashes`. + The interpretation of backslashes in the glob pattern remains unchanged with + the new option, but forward slashes match backslashes when activated (#199) + +1.10.2 (09-Sep-2021) +-------------------- + +* Fix missing aliases introduced in 1.10.1 + +1.10.1 (08-Sep-2021) +-------------------- + +* Glob: add optional argument `?backslash_escapes` to control interpretation of + backslashes (useful under Windows) (#197, #198) + +* Restore accidentally deleted `*_seq` deprecated aliases. + +1.10.0 (25-Aug-2021) +-------------------- + +* Add the `[:alpha:]` character class in `Re.Perl` (#169) +* Double asterisk (`**`) in `Re.Glob` (#172) + Like `*` but also match `/` characters when `pathname` is set. +* Double asterisk should match 0 or more directories unless in trailing + position. (#192, fixes #185) + 1.9.0 (05-Apr-2019) ------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/Makefile new/ocaml-re-1.10.3/Makefile --- old/ocaml-re-1.9.0/Makefile 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/Makefile 2021-09-13 21:26:15.000000000 +0200 @@ -16,3 +16,14 @@ .PHONY: all-supported-ocaml-versions all-supported-ocaml-versions: dune build @runtest --workspace dune-workspace.dev + +.PHONY: release +release: ## Release on Opam + dune-release distrib --skip-build --skip-lint --skip-tests + dune-release publish distrib --verbose + dune-release opam pkg + dune-release opam submit + +.PHONY: nix +nix: + nix-shell -A resolve default.nix diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/benchmarks/.merlin new/ocaml-re-1.10.3/benchmarks/.merlin --- old/ocaml-re-1.9.0/benchmarks/.merlin 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/benchmarks/.merlin 1970-01-01 01:00:00.000000000 +0100 @@ -1,3 +0,0 @@ -S ../lib -B ../_build/** -PKG core_bench diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/benchmarks/benchmark.ml new/ocaml-re-1.10.3/benchmarks/benchmark.ml --- old/ocaml-re-1.9.0/benchmarks/benchmark.ml 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/benchmarks/benchmark.ml 2021-09-13 21:26:15.000000000 +0200 @@ -1,5 +1,5 @@ -open Core.Std -open Core_bench.Std +open Core +open Core_bench module Http = struct open Re @@ -63,7 +63,7 @@ match String.strip s with | "" -> None | s -> Some s) - |> List.map ~f:Re_glob.glob + |> List.map ~f:Re.Glob.glob |> Re.alt let tex_ignore_filesnames = In_channel.read_lines "benchmarks/files" @@ -82,7 +82,7 @@ (* Taken from https://github.com/rgrinberg/ocaml-uri/blob/903ef1010f9808d6f3f6d9c1fe4b4eabbd76082d/lib/uri.ml*) let uri_reference = - Re_posix.re "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?" + Re.Posix.re "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?" let uris = [ "https://google.com" @@ -120,8 +120,8 @@ let rec drain_gen gen = match gen () with - | None -> () - | Some _ -> drain_gen gen + | Seq.Nil -> () + | Cons (_, tail) -> drain_gen tail let benchmarks = let benches = @@ -150,7 +150,7 @@ ) ; Test.create ~name:"all_gen group" (fun () -> http_requests - |> Re.all_gen requests_g + |> Re.Seq.all requests_g |> drain_gen ) ] |> Test.create_group ~name:"auto" in diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/default.nix new/ocaml-re-1.10.3/default.nix --- old/ocaml-re-1.9.0/default.nix 1970-01-01 01:00:00.000000000 +0100 +++ new/ocaml-re-1.10.3/default.nix 2021-09-13 21:26:15.000000000 +0200 @@ -0,0 +1,3 @@ +# standalone derivation, for nix-build, nix-shell, etc +{ pkgs ? import <nixpkgs> {}, opam2nix ? import ./nix/opam2nix.nix }: +pkgs.callPackage ./nix { inherit opam2nix; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/dune-project new/ocaml-re-1.10.3/dune-project --- old/ocaml-re-1.9.0/dune-project 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/dune-project 2021-09-13 21:26:15.000000000 +0200 @@ -1,3 +1,3 @@ -(lang dune 1.0) +(lang dune 2.0) (name re) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/dune-workspace.dev new/ocaml-re-1.10.3/dune-workspace.dev --- old/ocaml-re-1.9.0/dune-workspace.dev 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/dune-workspace.dev 2021-09-13 21:26:15.000000000 +0200 @@ -5,4 +5,9 @@ (context (opam (switch 4.04.2))) (context (opam (switch 4.05.0))) (context (opam (switch 4.06.1))) -(context (opam (switch 4.07.0))) \ No newline at end of file +(context (opam (switch 4.07.1))) +(context (opam (switch 4.08.1))) +(context (opam (switch 4.09.1))) +(context (opam (switch 4.10.2))) +(context (opam (switch 4.11.2))) +(context (opam (switch 4.12.0))) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/lib/automata.ml new/ocaml-re-1.10.3/lib/automata.ml --- old/ocaml-re-1.9.0/lib/automata.ml 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/lib/automata.ml 2021-09-13 21:26:15.000000000 +0200 @@ -254,11 +254,11 @@ | TSeq (l', x, _kind) -> Format.fprintf ch "@[<2>(Seq@ "; print_state_lst ch l' x; - Format.fprintf ch " %a)@]" pp x + Format.fprintf ch "@ %a)@]" pp x | TExp (marks, {def = Eps; _}) -> - Format.fprintf ch "(Exp %d (%a) (eps))" y.id Marks.pp_marks marks + Format.fprintf ch "@[<2>(Exp@ %d@ (%a)@ (eps))@]" y.id Marks.pp_marks marks | TExp (marks, x) -> - Format.fprintf ch "(Exp %d (%a) %a)" x.id Marks.pp_marks marks pp x + Format.fprintf ch "@[<2>(Exp@ %d@ (%a)@ %a)@]" x.id Marks.pp_marks marks pp x and print_state_lst ch l y = match l with @@ -268,7 +268,7 @@ print_state_rec ch e y; List.iter (fun e -> - Format.fprintf ch " | "; + Format.fprintf ch "@ | "; print_state_rec ch e y) rem diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/lib/core.ml new/ocaml-re-1.10.3/lib/core.ml --- old/ocaml-re-1.9.0/lib/core.ml 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/lib/core.ml 2021-09-13 21:26:15.000000000 +0200 @@ -1177,24 +1177,23 @@ | End_of_str -> "" in witness (handle_case false t) -type 'a seq = 'a Seq.t module Seq = Rseq module List = Rlist module Group = Group (** {2 Deprecated functions} *) +let split_full_seq = Seq.split_full +let split_seq = Seq.split +let matches_seq = Seq.matches +let all_seq = Seq.all + type 'a gen = 'a Gen.gen let all_gen = Gen.all let matches_gen = Gen.matches let split_gen = Gen.split let split_full_gen = Gen.split_full -let all_seq = Seq.all -let matches_seq = Seq.matches -let split_seq = Seq.split -let split_full_seq = Seq.split_full - type substrings = Group.t diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/lib/core.mli new/ocaml-re-1.10.3/lib/core.mli --- old/ocaml-re-1.9.0/lib/core.mli 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/lib/core.mli 2021-09-13 21:26:15.000000000 +0200 @@ -20,7 +20,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) -(** Module [Re]: regular expressions commons *) +(** Module [Re]: code for creating and using regular expressions, + independently of regular expression syntax. *) type t (** Regular expression *) @@ -31,11 +32,16 @@ (** Manipulate matching groups. *) module Group : sig type t - (** Information about groups in a match. *) + (** Information about groups in a match. As is conventional, every + match implicitly has a group 0 that covers the whole match, and + explicit groups are numbered from 1. *) val get : t -> int -> string (** Raise [Not_found] if the group did not match *) + val get_opt : t -> int -> string option + (** Similar to {!get}, but returns an option instead of using an exception. *) + val offset : t -> int -> int * int (** Raise [Not_found] if the group did not match *) @@ -69,35 +75,51 @@ used to match strings, e.g. with {!exec}. *) val exec : - ?pos:int -> (* Default: 0 *) - ?len:int -> (* Default: -1 (until end of string) *) + ?pos:int -> (** Default: 0 *) + ?len:int -> (** Default: -1 (until end of string) *) re -> string -> Group.t -(** [exec re str] matches [str] against the compiled expression [re], +(** [exec re str] searches [str] for a match of the compiled expression [re], and returns the matched groups if any. + + More specifically, when a match exists, [exec] returns a match that + starts at the earliest position possible. If multiple such matches are + possible, the one specified by the match semantics described below is + returned. + @param pos optional beginning of the string (default 0) @param len length of the substring of [str] that can be matched (default [-1], - meaning to the end of the string + meaning to the end of the string) @raise Not_found if the regular expression can't be found in [str] + + Note that [exec re str ~pos ~len] is not equivalent to [exec re + (String.sub str pos len)]. This transformation changes the meaning + of some constructs ({!bos}, {!eos}, {!whole_string} and {!leol}), and + zero-width assertions like {!bow} or {!eow} look at characters before + [pos] and after [pos + len]. *) val exec_opt : - ?pos:int -> (* Default: 0 *) - ?len:int -> (* Default: -1 (until end of string) *) + ?pos:int -> (** Default: 0 *) + ?len:int -> (** Default: -1 (until end of string) *) re -> string -> Group.t option (** Similar to {!exec}, but returns an option instead of using an exception. *) val execp : - ?pos:int -> (* Default: 0 *) - ?len:int -> (* Default: -1 (until end of string) *) + ?pos:int -> (** Default: 0 *) + ?len:int -> (** Default: -1 (until end of string) *) re -> string -> bool (** Similar to {!exec}, but returns [true] if the expression matches, - and [false] if it doesn't *) + and [false] if it doesn't. This function is more efficient than + calling {!exec} or {!exec_opt} and ignoring the returned group. + *) val exec_partial : - ?pos:int -> (* Default: 0 *) - ?len:int -> (* Default: -1 (until end of string) *) + ?pos:int -> (** Default: 0 *) + ?len:int -> (** Default: -1 (until end of string) *) re -> string -> [ `Full | `Partial | `Mismatch ] -(** More detailed version of {!exec_p} *) +(** More detailed version of {!exec_p}. [`Full] is equivalent to [true], + while [`Mismatch] and [`Partial] are equivalent to [false], but [`Partial] + indicates the input string could be extended to create a match. *) (** Marks *) module Mark : sig @@ -125,36 +147,6 @@ | `Delim of Group.t (** Delimiter *) ] -type 'a seq = 'a Seq.t - -module Seq : sig - val all : - ?pos:int -> (** Default: 0 *) - ?len:int -> - re -> string -> Group.t Seq.t - (** Same as {!all} but returns an iterator - @since NEXT_RELEASE *) - - val matches : - ?pos:int -> (** Default: 0 *) - ?len:int -> - re -> string -> string Seq.t - (** Same as {!matches}, but returns an iterator - @since NEXT_RELEASE *) - - val split : - ?pos:int -> (** Default: 0 *) - ?len:int -> - re -> string -> string Seq.t - (** @since NEXT_RELEASE *) - - val split_full : - ?pos:int -> (** Default: 0 *) - ?len:int -> - re -> string -> split_token Seq.t - (** @since NEXT_RELEASE *) -end - val all : ?pos:int -> ?len:int -> re -> string -> Group.t list (** Repeatedly calls {!exec} on the given string, starting at given position and length.*) @@ -164,7 +156,7 @@ val all_gen : ?pos:int -> ?len:int -> re -> string -> Group.t gen [@@ocaml.deprecated "Use Seq.all"] -val all_seq : ?pos:int -> ?len:int -> re -> string -> Group.t seq +val all_seq : ?pos:int -> ?len:int -> re -> string -> Group.t Seq.t [@@ocaml.deprecated "Use Seq.all"] val matches : ?pos:int -> ?len:int -> re -> string -> string list @@ -174,7 +166,7 @@ val matches_gen : ?pos:int -> ?len:int -> re -> string -> string gen [@@ocaml.deprecated "Use Seq.matches"] -val matches_seq : ?pos:int -> ?len:int -> re -> string -> string seq +val matches_seq : ?pos:int -> ?len:int -> re -> string -> string Seq.t [@@ocaml.deprecated "Use Seq.matches"] val split : ?pos:int -> ?len:int -> re -> string -> string list @@ -185,7 +177,7 @@ val split_gen : ?pos:int -> ?len:int -> re -> string -> string gen [@@ocaml.deprecated "Use Seq.split"] -val split_seq : ?pos:int -> ?len:int -> re -> string -> string seq +val split_seq : ?pos:int -> ?len:int -> re -> string -> string Seq.t [@@ocaml.deprecated "Use Seq.split"] val split_full : ?pos:int -> ?len:int -> re -> string -> split_token list @@ -196,15 +188,43 @@ val split_full_gen : ?pos:int -> ?len:int -> re -> string -> split_token gen [@@ocaml.deprecated "Use Seq.split_full"] -val split_full_seq : ?pos:int -> ?len:int -> re -> string -> split_token seq +val split_full_seq : ?pos:int -> ?len:int -> re -> string -> split_token Seq.t [@@ocaml.deprecated "Use Seq.split_full"] +module Seq : sig + val all : + ?pos:int -> (** Default: 0 *) + ?len:int -> + re -> string -> Group.t Seq.t + (** Same as {!all} but returns an iterator + @since 1.10.0 *) + + val matches : + ?pos:int -> (** Default: 0 *) + ?len:int -> + re -> string -> string Seq.t + (** Same as {!matches}, but returns an iterator + @since 1.10.0 *) + + val split : + ?pos:int -> (** Default: 0 *) + ?len:int -> + re -> string -> string Seq.t + (** @since 1.10.0 *) + + val split_full : + ?pos:int -> (** Default: 0 *) + ?len:int -> + re -> string -> split_token Seq.t + (** @since 1.10.0 *) +end + val replace : ?pos:int -> (** Default: 0 *) ?len:int -> ?all:bool -> (** Default: true. Otherwise only replace first occurrence *) re -> (** matched groups *) - f:(Group.t -> string) -> (* how to replace *) + f:(Group.t -> string) -> (** how to replace *) string -> (** string to replace in *) string (** [replace ~all re ~f s] iterates on [s], and replaces every occurrence @@ -231,7 +251,12 @@ (** {2 Basic operations on regular expressions} *) val alt : t list -> t -(** Alternative *) +(** Alternative. + + [alt []] is equivalent to {!empty}. + + By default, the leftmost match is preferred (see match semantics below). +*) val seq : t list -> t (** Sequence *) @@ -257,7 +282,10 @@ val opt : t -> t (** 0 or 1 matches *) -(** {2 String, line, word} *) +(** {2 String, line, word} + + We define a word as a sequence of latin1 letters, digits and underscore. +*) val bol : t (** Beginning of line *) @@ -272,19 +300,35 @@ (** End of word *) val bos : t -(** Beginning of string *) +(** Beginning of string. This differs from {!start} because it matches + the beginning of the input string even when using [~pos] arguments: + + {[ + let b = execp (compile (seq [ bos; str "a" ])) "aa" ~pos:1 in + assert (not b) + ]} +*) val eos : t -(** End of string *) +(** End of string. This is different from {!stop} in the way described + in {!bos}. *) val leol : t (** Last end of line or end of string *) val start : t -(** Initial position *) +(** Initial position. This differs from {!bos} because it takes into + account the [~pos] arguments: + + {[ + let b = execp (compile (seq [ start; str "a" ])) "aa" ~pos:1 in + assert b + ]} +*) val stop : t -(** Final position *) +(** Final position. This is different from {!eos} in the way described + in {!start}. *) val word : t -> t (** Word *) @@ -293,38 +337,77 @@ (** Not at a word boundary *) val whole_string : t -> t -(** Only matches the whole string *) +(** Only matches the whole string, i.e. [fun t -> seq [ eos; t; bos ]]. *) -(** {2 Match semantics} *) +(** {2 Match semantics} + + A regular expression frequently matches a string in multiple ways. For + instance [exec (compile (opt (str "a"))) "ab"] can match "" or "a". Match + semantic can be modified with the functions below, allowing one to choose + which of these is preferable. + + By default, the leftmost branch of alternations is preferred, and repetitions + are greedy. + + Note that the existence of matches cannot be changed by specifying match + semantics. [seq [ bos; str "a"; non_greedy (opt (str "b")); eos ]] will + match when applied to "ab". However if [seq [ bos; str "a"; non_greedy (opt + (str "b")) ]] is applied to "ab", it will match "a" rather than "ab". + + Also note that multiple match semantics can conflict. In this case, the one + executed earlier takes precedence. For instance, any match of [shortest (seq + [ bos; group (rep (str "a")); group (rep (str "a")); eos ])] will always have + an empty first group. Conversely, if we use [longest] instead of [shortest], + the second group will always be empty. +*) val longest : t -> t -(** Longest match *) +(** Longest match semantics. That is, matches will match as many bytes as + possible. If multiple choices match the maximum amount of bytes, the one + respecting the inner match semantics is preferred. *) val shortest : t -> t -(** Shortest match *) +(** Same as {!longest}, but matching the least number of bytes. *) val first : t -> t -(** First match *) - -(** {2 Repeated match modifiers} *) +(** First match semantics for alternations (not repetitions). That is, matches + will prefer the leftmost branch of the alternation that matches the text. *) val greedy : t -> t -(** Greedy *) +(** Greedy matches for repetitions ({!opt}, {!rep}, {!rep1}, {!repn}): they will + match as many times as possible. *) val non_greedy : t -> t -(** Non-greedy *) +(** Non-greedy matches for repetitions ({!opt}, {!rep}, {!rep1}, {!repn}): they + will match as few times as possible. *) (** {2 Groups (or submatches)} *) val group : t -> t -(** Delimit a group *) +(** Delimit a group. The group is considered as matching if it is used at least + once (it may be used multiple times if is nested inside {!rep} for + instance). If it is used multiple times, the last match is what gets + captured. *) val no_group : t -> t (** Remove all groups *) val nest : t -> t -(** when matching against [nest e], only the group matching in the - last match of e will be considered as matching *) +(** When matching against [nest e], only the group matching in the + last match of e will be considered as matching. + + For instance: + {[ + let re = compile (rep1 (nest (alt [ group (str "a"); str "b" ]))) in + let group = Re.exec re "ab" in + assert (Group.get_opt group 1 = None); + + (* same thing but without [nest] *) + let re = compile (rep1 (alt [ group (str "a"); str "b" ])) in + let group = Re.exec re "ab" in + assert (Group.get_opt group 1 = Some "a"); + ]} +*) @@ -374,10 +457,12 @@ (** {2 Case modifiers} *) val case : t -> t -(** Case sensitive matching *) +(** Case sensitive matching. Note that this works on latin1, not ascii and not + utf8. *) val no_case : t -> t -(** Case insensitive matching *) +(** Case insensitive matching. Note that this works on latin1, not ascii and not + utf8. *) (****) @@ -415,11 +500,14 @@ val view : outer -> t end with type outer := t -(** {2 Experimental functions}. *) +(** {2 Experimental functions} *) val witness : t -> string -(** [witness r] generates a string [s] such that [execp (compile r) s] is - true *) +(** [witness r] generates a string [s] such that [execp (compile r) s] is true. + + Be warned that this function is buggy because it ignores zero-width + assertions like beginning of words. As a result it can generate incorrect + results. *) (** {2 Deprecated functions} *) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/lib/glob.ml new/ocaml-re-1.10.3/lib/glob.ml --- old/ocaml-re-1.9.0/lib/glob.ml 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/lib/glob.ml 2021-09-13 21:26:15.000000000 +0200 @@ -34,10 +34,11 @@ | Any_but of enclosed list | One | Many + | ManyMany type t = piece list -let of_string s : t = +let of_string ~double_asterisk s : t = let i = ref 0 in let l = String.length s in let eos () = !i = l in @@ -47,6 +48,26 @@ r in + (** + [read_ahead pattern] will attempt to read [pattern] and will return [true] if it was successful. + If it fails, it will return [false] and not increment the read index. + *) + let read_ahead pattern = + let pattern_len = String.length pattern in + (* if the pattern we are looking for exeeds the remaining length of s, return false immediately *) + if !i + pattern_len >= l then + false + else + try + for j = 0 to pattern_len - 1 do + let found = not (eos ()) && s.[!i + j] = pattern.[j] in + if not found then raise_notrace Exit; + done; + i := !i + pattern_len; + true + with | Exit -> false + in + let char () = ignore (read '\\' : bool); if eos () then raise Parse_error; @@ -74,8 +95,12 @@ in let piece () = - if read '*' - then Many + if double_asterisk && read_ahead "/**" && not (eos ()) + then ManyMany + else if read '*' + then if double_asterisk && read '*' + then ManyMany + else Many else if read '?' then One else if not (read '[') @@ -127,15 +152,17 @@ am_at_start_of_component : bool; (* true at start of pattern or immediately after '/' *) pathname : bool; + match_backslashes : bool; period : bool; } - let create ~period ~pathname remaining = + let create ~period ~pathname ~match_backslashes remaining = { re_pieces = []; am_at_start_of_pattern = true; am_at_start_of_component = true; pathname; + match_backslashes; period; remaining; } @@ -148,6 +175,9 @@ let explicit_slash t = t.pathname + let slashes t = + if t.match_backslashes then ['/'; '\\'] else ['/'] + let append ?(am_at_start_of_component=false) t piece = { t with re_pieces = piece :: t.re_pieces; @@ -163,10 +193,10 @@ | piece :: remaining -> Some (piece, { t with remaining }) end -let one ~explicit_slash ~explicit_period = +let one ~explicit_slash ~slashes ~explicit_period = Re.compl ( List.concat [ - if explicit_slash then [Re.char '/'] else []; + if explicit_slash then List.map Re.char slashes else []; if explicit_period then [Re.char '.'] else []; ] ) @@ -176,39 +206,66 @@ | Char c -> Re.char c | Range (low, high) -> Re.rg low high -let enclosed_set ~explicit_slash ~explicit_period kind set = +let enclosed_set ~explicit_slash ~slashes ~explicit_period kind set = let set = List.map enclosed set in let enclosure = match kind with | `Any_of -> Re.alt set | `Any_but -> Re.compl set in - Re.inter [enclosure; one ~explicit_slash ~explicit_period] + Re.inter [enclosure; one ~explicit_slash ~slashes ~explicit_period] let exactly state c = - State.append state (Re.char c) ~am_at_start_of_component:(c = '/') + let slashes = State.slashes state in + let am_at_start_of_component = List.mem c slashes in + let chars = if am_at_start_of_component then slashes else [c] in + State.append state (Re.alt (List.map Re.char chars)) ~am_at_start_of_component + +let many_many state = + let explicit_period = state.State.period && state.State.pathname in + let first_explicit_period = State.explicit_period state in + let slashes = State.slashes state in + let match_component ~explicit_period = + Re.seq [ + one ~explicit_slash:true ~slashes ~explicit_period; + Re.rep (one ~explicit_slash:true ~slashes ~explicit_period:false); + ] + in + (* We must match components individually when [period] flag is set, + making sure to not match ["foo/.bar"]. *) + State.append state ( + Re.seq [ + Re.opt (match_component ~explicit_period:first_explicit_period); + Re.rep ( + Re.seq [ + Re.alt (List.map Re.char slashes); + Re.opt (match_component ~explicit_period); + ] + ); + ]) let many (state : State.t) = let explicit_slash = State.explicit_slash state in let explicit_period = State.explicit_period state in + let slashes = State.slashes state in (* Whether we must explicitly match period depends on the surrounding characters, but slashes are easy to explicit match. This conditional splits out some simple cases. *) if not explicit_period then begin - State.append state (Re.rep (one ~explicit_slash ~explicit_period)) + State.append state (Re.rep (one ~explicit_slash ~slashes ~explicit_period)) end else if not explicit_slash then begin (* In this state, we explicitly match periods only at the very beginning *) State.append state (Re.opt ( Re.seq [ - one ~explicit_slash:false ~explicit_period; - Re.rep (one ~explicit_slash:false ~explicit_period:false); + one ~explicit_slash:false ~slashes ~explicit_period; + Re.rep (one ~explicit_slash:false ~slashes ~explicit_period:false); ] )) end else begin let not_empty = Re.seq [ - one ~explicit_slash:true ~explicit_period:true; - Re.rep (one ~explicit_slash:true ~explicit_period:false); + one ~explicit_slash:true ~slashes ~explicit_period:true; + Re.rep (one ~explicit_slash:true ~slashes ~explicit_period:false); ] in (* [maybe_empty] is the default translation of Many, except in some special cases. @@ -216,11 +273,11 @@ let maybe_empty = Re.opt not_empty in let enclosed_set state kind set = State.append state (Re.alt [ - enclosed_set kind set ~explicit_slash:true ~explicit_period:true; + enclosed_set kind set ~explicit_slash:true ~slashes ~explicit_period:true; Re.seq [ not_empty; (* Since [not_empty] matched, subsequent dots are not leading. *) - enclosed_set kind set ~explicit_slash:true ~explicit_period:false; + enclosed_set kind set ~explicit_slash:true ~slashes ~explicit_period:false; ]; ]) in @@ -241,6 +298,8 @@ | Some (One, state) -> State.append state not_empty | Some (Any_of enclosed, state) -> enclosed_set state `Any_of enclosed | Some (Any_but enclosed, state) -> enclosed_set state `Any_but enclosed + (* * then ** === ** *) + | Some (ManyMany, state) -> many_many state in lookahead state end @@ -248,32 +307,36 @@ let piece state piece = let explicit_slash = State.explicit_slash state in let explicit_period = State.explicit_period state in + let slashes = State.slashes state in match piece with - | One -> State.append state (one ~explicit_slash ~explicit_period) + | One -> State.append state (one ~explicit_slash ~slashes ~explicit_period) | Many -> many state | Any_of enclosed -> - State.append state (enclosed_set `Any_of ~explicit_slash ~explicit_period enclosed) + State.append state (enclosed_set `Any_of ~explicit_slash ~slashes ~explicit_period enclosed) | Any_but enclosed -> - State.append state (enclosed_set `Any_but ~explicit_slash ~explicit_period enclosed) + State.append state (enclosed_set `Any_but ~explicit_slash ~slashes ~explicit_period enclosed) | Exactly c -> exactly state c + | ManyMany -> many_many state -let glob ~pathname ~period glob = +let glob ~pathname ~match_backslashes ~period glob = let rec loop state = match State.next state with | None -> State.to_re state | Some (p, state) -> loop (piece state p) in - loop (State.create ~pathname ~period glob) + loop (State.create ~pathname ~match_backslashes ~period glob) let glob ?(anchored = false) ?(pathname = true) + ?(match_backslashes = false) ?(period = true) ?(expand_braces = false) + ?(double_asterisk = true) s = let to_re s = - let re = glob ~pathname ~period (of_string s) in + let re = glob ~pathname ~match_backslashes ~period (of_string ~double_asterisk s) in if anchored then Re.whole_string re else re diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/lib/glob.mli new/ocaml-re-1.10.3/lib/glob.mli --- old/ocaml-re-1.9.0/lib/glob.mli 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/lib/glob.mli 2021-09-13 21:26:15.000000000 +0200 @@ -27,8 +27,10 @@ val glob : ?anchored:bool -> ?pathname:bool -> + ?match_backslashes:bool -> ?period:bool -> ?expand_braces:bool -> + ?double_asterisk:bool -> string -> Core.t (** Implements the semantics of shells patterns. The returned regular @@ -48,6 +50,11 @@ and not by an asterisk ('*') or a question mark ('?') metacharacter, nor by a bracket expression ('[]') containing a slash. Defaults to true. + [match_backslashes]: If this flag is set, a forward slash will also match a + backslash (useful when globbing Windows paths). Note that a backslash in the + pattern will continue to escape the following character. Defaults to + [false]. + [period]: If this flag is set, a leading period in string has to be matched exactly by a period in pattern. A period is considered to be leading if it is the first character in string, or if both [pathname] is set and the period immediately follows a @@ -55,7 +62,11 @@ If [expand_braces] is true, braced sets will expand into multiple globs, e.g. a\{x,y\}b\{1,2\} matches axb1, axb2, ayb1, ayb2. As specified for bash, brace - expansion is purely textual and can be nested. Defaults to false. *) + expansion is purely textual and can be nested. Defaults to false. + + [double_asterisk]: If this flag is set, double asterisks ('**') will match slash + characters, even if [pathname] is set. The [period] flag still applies. Default to + true. *) val glob' : ?anchored:bool -> bool -> string -> Core.t (** Same, but allows to choose whether dots at the beginning of a diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/lib/group.ml new/ocaml-re-1.10.3/lib/group.ml --- old/ocaml-re-1.9.0/lib/group.ml 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/lib/group.ml 2021-09-13 21:26:15.000000000 +0200 @@ -30,6 +30,11 @@ let idx = t.marks.(2 * i) in idx <> -1 +let get_opt t i = + if test t i + then Some (get t i) + else None + let dummy_offset = (-1, -1) let all_offset t = diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/lib/group.mli new/ocaml-re-1.10.3/lib/group.mli --- old/ocaml-re-1.9.0/lib/group.mli 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/lib/group.mli 2021-09-13 21:26:15.000000000 +0200 @@ -27,6 +27,9 @@ val get : t -> int -> string (** Raise [Not_found] if the group did not match *) +val get_opt : t -> int -> string option +(** Similar to {!get}, but returns an option instead of using an exception. *) + val offset : t -> int -> int * int (** Raise [Not_found] if the group did not match *) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/lib/perl.ml new/ocaml-re-1.10.3/lib/perl.ml --- old/ocaml-re-1.9.0/lib/perl.ml 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/lib/perl.ml 2021-09-13 21:26:15.000000000 +0200 @@ -26,6 +26,7 @@ exception Not_supported let posix_class_of_string = function + | "alpha" -> Re.alpha | "alnum" -> Re.alnum | "ascii" -> Re.ascii | "blank" -> Re.blank @@ -42,11 +43,11 @@ | class_ -> invalid_arg ("Invalid pcre class: " ^ class_) let posix_class_strings = - [ "alnum" ; "ascii" ; "blank" - ; "cntrl" ; "digit" ; "lower" - ; "print" ; "space" ; "upper" - ; "word" ; "punct" ; "graph" - ; "xdigit" ] + [ "alpha" ; "alnum" ; "ascii" + ; "blank" ; "cntrl" ; "digit" + ; "lower" ; "print" ; "space" + ; "upper" ; "word" ; "punct" + ; "graph" ; "xdigit" ] let parse multiline dollar_endonly dotall ungreedy s = let i = ref 0 in diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/lib/str.ml new/ocaml-re-1.10.3/lib/str.ml --- old/ocaml-re-1.9.0/lib/str.ml 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/lib/str.ml 2021-09-13 21:26:15.000000000 +0200 @@ -203,16 +203,18 @@ let global_substitute expr repl_fun text = let rec replace accu start last_was_empty = - try - let startpos = if last_was_empty then start + 1 else start in - if startpos > String.length text then raise Not_found; - let pos = search_forward expr text startpos in - let end_pos = match_end () in - let repl_text = repl_fun text in - replace (repl_text :: String.sub text start (pos-start) :: accu) - end_pos (end_pos = pos) - with Not_found -> - (string_after text start) :: accu in + let startpos = if last_was_empty then start + 1 else start in + if startpos > String.length text then + (string_after text start) :: accu + else + match search_forward expr text startpos with + | pos -> + let end_pos = match_end () in + let repl_text = repl_fun text in + replace (repl_text :: String.sub text start (pos-start) :: accu) + end_pos (end_pos = pos) + | exception Not_found -> (string_after text start) :: accu + in String.concat "" (List.rev (replace [] 0 false)) let global_replace expr repl text = diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/lib/str.mli new/ocaml-re-1.10.3/lib/str.mli --- old/ocaml-re-1.9.0/lib/str.mli 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/lib/str.mli 2021-09-13 21:26:15.000000000 +0200 @@ -52,10 +52,11 @@ [s] and nothing else. *) val regexp_string: string -> regexp -val regexp_string_case_fold: string -> regexp (** [Str.regexp_string s] returns a regular expression - that matches exactly [s] and nothing else. - [Str.regexp_string_case_fold] is similar, but the regexp + that matches exactly [s] and nothing else. *) + +val regexp_string_case_fold: string -> regexp +(** [Str.regexp_string_case_fold] is similar to [Str.regexp_string], but the regexp matches in a case-insensitive way. *) (** {2 String matching and searching} *) @@ -88,12 +89,14 @@ that was passed to the matching or searching function. *) val match_beginning: unit -> int -val match_end: unit -> int (** [match_beginning ()] returns the position of the first character of the substring that was matched by [string_match], - [search_forward] or [search_backward]. [match_end ()] returns - the position of the character following the last character of - the matched substring. *) + [search_forward] or [search_backward]. *) + +val match_end: unit -> int +(** [match_end ()] returns the position of the character following the + last character of the substring that was matched by [string_match], + [search_forward] or [search_backward]. *) val matched_group: int -> string -> string (** [matched_group n s] returns the substring of [s] that was matched @@ -109,14 +112,14 @@ because the first group itself was not matched. *) val group_beginning: int -> int -val group_end: int -> int (** [group_beginning n] returns the position of the first character - of the substring that was matched by the [n]th group of - the regular expression. [group_end n] returns - the position of the character following the last character of - the matched substring. Both functions raise [Not_found] - if the [n]th group of the regular expression - was not matched. *) + of the substring that was matched by the [n]th group of the regular expression. + Raises [Not_found] if the [n]th group of the regular expression was not matched. *) + +val group_end: int -> int +(** [group_end n] returns the position of the character following + the last character of the matched substring. + Raises [Not_found] if the [n]th group of the regular expression was not matched. *) (** {2 Replacement} *) @@ -164,23 +167,35 @@ where [n] is the extra integer parameter. *) val split_delim: regexp -> string -> string list +(** Same as [split], but occurrences of the delimiter at the beginning + and at the end of the string are recognized and returned as empty strings + in the result. + For instance, [split_delim (regexp " ") " abc "] returns [[""; "abc"; ""]], + while [split] with the same arguments returns [["abc"]]. *) + val bounded_split_delim: regexp -> string -> int -> string list -(** Same as [split] and [bounded_split], but occurrences of the - delimiter at the beginning and at the end of the string are - recognized and returned as empty strings in the result. - For instance, [split_delim (regexp " ") " abc "] - returns [[""; "abc"; ""]], while [split] with the same - arguments returns [["abc"]]. *) +(** Same as [bounded_split] and [split_delim], but occurrences of + the delimiter at the beginning and at the end of the string are recognized + and returned as empty strings in the result. + For instance, [split_delim (regexp " ") " abc "] returns [[""; "abc"; ""]], + while [split] with the same arguments returns [["abc"]]. *) type split_result = Text of string | Delim of string val full_split: regexp -> string -> split_result list +(** Same as [split_delim], but returns the delimiters + as well as the substrings contained between delimiters. + The former are tagged [Delim] in the result list; + the latter are tagged [Text]. + For instance, [full_split (regexp "[{}]") "{ab}"] returns + [[Delim "{"; Text "ab"; Delim "}"]]. *) + val bounded_full_split: regexp -> string -> int -> split_result list (** Same as [split_delim] and [bounded_split_delim], but returns - the delimiters as well as the substrings contained between - delimiters. The former are tagged [Delim] in the result list; - the latter are tagged [Text]. For instance, - [full_split (regexp "[{}]") "{ab}"] returns + the delimiters as well as the substrings contained between delimiters. + The former are tagged [Delim] in the result list; + the latter are tagged [Text]. + For instance, [full_split (regexp "[{}]") "{ab}"] returns [[Delim "{"; Text "ab"; Delim "}"]]. *) (** {2 Extracting substrings} *) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/lib_test/fort_unit/fort_unit.ml new/ocaml-re-1.10.3/lib_test/fort_unit/fort_unit.ml --- old/ocaml-re-1.9.0/lib_test/fort_unit/fort_unit.ml 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/lib_test/fort_unit/fort_unit.ml 2021-09-13 21:26:15.000000000 +0200 @@ -49,6 +49,8 @@ expect_equal_app ?msg ~printer:string_of_bool f x g y let expect_eq_str ?msg f x g y = expect_equal_app ?msg ~printer:str_printer f x g y +let expect_eq_str_opt ?msg f x g y = + expect_equal_app ?msg ~printer:(opt_printer str_printer) f x g y let expect_eq_ofs ?msg f x g y = expect_equal_app ?msg ~printer:ofs_printer f x g y let expect_eq_arr_str ?msg f x g y = diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/lib_test/test_glob.ml new/ocaml-re-1.10.3/lib_test/test_glob.ml --- old/ocaml-re-1.9.0/lib_test/test_glob.ml 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/lib_test/test_glob.ml 2021-09-13 21:26:15.000000000 +0200 @@ -85,4 +85,74 @@ assert (re_match (glob ~expand_braces:true "{foo,far}bar") "farbar" ); assert (re_mismatch (glob ~expand_braces:true "{foo,far}bar") "{foo,far}bar"); + (* Double asterisk *) + let anchored = true in + assert (re_match (glob ~anchored "**") "foobar"); + assert (re_match (glob ~anchored "**") "foo/bar"); + assert (re_match (glob ~anchored "**/bar") "foo/bar"); + assert (re_match (glob ~anchored "**/bar") "foo/far/bar"); + assert (re_mismatch (glob ~anchored "foo/**") "foo"); + assert (re_match (glob ~anchored "foo/**") "foo/bar"); + assert (re_match (glob ~anchored "foo/**") "foo/far/bar"); + assert (re_match (glob ~anchored "foo/**/bar") "foo/far/bar"); + assert (re_match (glob ~anchored "foo/**/bar") "foo/far/oof/bar"); + assert (re_match (glob ~anchored "foo/**bar") "foo/far/oofbar"); + assert (re_match (glob ~anchored "foo/**bar") "foo/bar"); + assert (re_match (glob ~anchored "foo/**bar") "foo/foobar"); + assert (re_match (glob ~anchored "/**") "//foo"); + assert (re_match (glob ~anchored "**") "foo//bar"); + + assert (re_match (glob ~anchored "foo/bar/**/*.ml") "foo/bar/baz/foobar.ml"); + assert (re_match (glob ~anchored "foo/bar/**/*.ml") "foo/bar/foobar.ml"); + + assert (re_match (glob ~anchored "foo/**/bar/**/baz") "foo/bar/baz"); + assert (re_match (glob ~anchored "foo/**/bar/**/baz") "foo/bar/x/y/z/baz"); + assert (re_match (glob ~anchored "foo/**/bar/**/baz") "foo/x/y/z/bar/baz"); + assert (re_match (glob ~anchored "foo/**/bar/**/baz") "foo/bar/x/bar/x/baz"); + assert (re_mismatch (glob ~anchored "foo/**/bar/**/baz") "foo/bar/../x/baz"); + assert (re_mismatch (glob ~anchored "foo/**/bar/**/baz") "foo/bar/./x/baz"); + + (* Interaction with [~period] *) + let period = true in + assert (re_mismatch (glob ~anchored ~period "**") ".foobar"); + assert (re_mismatch (glob ~anchored ~period "**") ".foo/bar"); + assert (re_mismatch (glob ~anchored ~period "foo/**") "foo/.bar"); + assert (re_mismatch (glob ~anchored ~period "**") "foo/.bar/bat"); + assert (re_mismatch (glob ~anchored ~period "foo/**/bat") "foo/.bar/bat"); + assert (re_mismatch (glob ~anchored ~period "/**/bat") "/foo/.bar/bat"); + assert (re_mismatch (glob ~anchored ~period "/**/bat") "/.bar/bat"); + assert (re_mismatch (glob ~anchored ~period "/**bat") "/bar/.bat"); + assert (re_match (glob ~anchored ~period ".**") ".foobar"); + assert (re_match (glob ~anchored ~period ".**") ".foo/bar"); + assert (re_match (glob ~anchored ~period "foo/.**") "foo/.bar"); + + let period = false in + assert (re_match (glob ~anchored ~period "**") ".foobar"); + assert (re_match (glob ~anchored ~period "**") ".foo/bar"); + assert (re_match (glob ~anchored ~period "foo/**") "foo/.bar"); + assert (re_match (glob ~anchored ~period "**") "foo/.bar/bat"); + assert (re_match (glob ~anchored ~period "foo/**/bat") "foo/.bar/bat"); + assert (re_match (glob ~anchored ~period "/**/bat") "/foo/.bar/bat"); + assert (re_match (glob ~anchored ~period "/**/bat") "/.bar/bat"); + assert (re_match (glob ~anchored ~period "/**bat") "/bar/.bat"); + + (* Backslash handling *) + let anchored = true in + let match_backslashes = false in + assert (re_mismatch (glob ~anchored ~match_backslashes "a/b/c") "a\\b/c"); + assert (re_match (glob ~anchored ~match_backslashes "a\\b") "ab"); + assert (re_match (glob ~anchored ~match_backslashes "a/*.ml") "a/b\\c.ml"); + assert (re_mismatch (glob ~anchored ~match_backslashes "a/b/*.ml") "a\\b\\c.ml"); + assert (re_mismatch (glob ~anchored ~match_backslashes "/") "\\"); + assert (re_mismatch (glob ~anchored ~match_backslashes "/?") "\\a"); + assert (re_match (glob ~anchored ~match_backslashes "a/**.ml") "a\\c\\.b.ml"); + let match_backslashes = true in + assert (re_match (glob ~anchored ~match_backslashes "a/b/c") "a\\b/c"); + assert (re_match (glob ~anchored ~match_backslashes "a\\b") "ab"); + assert (re_mismatch (glob ~anchored ~match_backslashes "a/*.ml") "a/b\\c.ml"); + assert (re_match (glob ~anchored ~match_backslashes "a/b/*.ml") "a\\b\\c.ml"); + assert (re_match (glob ~anchored ~match_backslashes "/") "\\"); + assert (re_match (glob ~anchored ~match_backslashes "/?") "\\a"); + assert (re_mismatch (glob ~anchored ~match_backslashes "a/**.ml") "a\\c\\.b.ml"); + run_test_suite "test_re"; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/lib_test/test_re.ml new/ocaml-re-1.10.3/lib_test/test_re.ml --- old/ocaml-re-1.9.0/lib_test/test_re.ml 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/lib_test/test_re.ml 2021-09-13 21:26:15.000000000 +0200 @@ -50,6 +50,14 @@ expect_eq_str not_found () (Group.get m) 4; ); + expect_pass "Group.get_opt" (fun () -> + expect_eq_str_opt id (Some "ab") (Group.get_opt m) 0; + expect_eq_str_opt id (Some "a") (Group.get_opt m) 1; + expect_eq_str_opt id None (Group.get_opt m) 2; + expect_eq_str_opt id (Some "b") (Group.get_opt m) 3; + expect_eq_str_opt id None (Group.get_opt m) 4; + ); + expect_pass "Group.offset" (fun () -> expect_eq_ofs id (0,2) (Group.offset m) 0; expect_eq_ofs id (0,1) (Group.offset m) 1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/nix/default.nix new/ocaml-re-1.10.3/nix/default.nix --- old/ocaml-re-1.9.0/nix/default.nix 1970-01-01 01:00:00.000000000 +0100 +++ new/ocaml-re-1.10.3/nix/default.nix 2021-09-13 21:26:15.000000000 +0200 @@ -0,0 +1,31 @@ +# paramaterised derivation with dependencies injected (callPackage style) +{ pkgs, stdenv, opam2nix }: +let + strings = pkgs.lib.strings; + args = { + inherit (pkgs.ocaml-ng.ocamlPackages_4_12) ocaml; + selection = ./opam-selection.nix; + src = builtins.filterSource (path: type: + let name = baseNameOf path; + in if type == "directory" then + name != ".git" && name != "_build" && name + != ".log" + else + strings.hasSuffix ".opam" name) ../.; + }; + opam-selection = opam2nix.build args; + localPackages = let contents = builtins.attrNames (builtins.readDir ../.); + in builtins.filter (strings.hasSuffix ".opam") contents; + resolve = opam2nix.resolve args (localPackages ++ [ + "ounit" + ]); + +in (builtins.listToAttrs (builtins.map (fname: + let packageName = strings.removeSuffix ".opam" fname; + in { + name = packageName; + value = builtins.getAttr packageName opam-selection; + }) localPackages)) // { + inherit resolve; + opam = opam-selection; + } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/nix/opam-selection.nix new/ocaml-re-1.10.3/nix/opam-selection.nix --- old/ocaml-re-1.9.0/nix/opam-selection.nix 1970-01-01 01:00:00.000000000 +0100 +++ new/ocaml-re-1.10.3/nix/opam-selection.nix 2021-09-13 21:26:15.000000000 +0200 @@ -0,0 +1,258 @@ +### This file is generated by opam2nix. + +self: +let + lib = self.lib; + pkgs = self.pkgs; + repoPath = self.repoPath; + repos = + { + opam-repository = + rec { + fetch = + { + owner = "ocaml"; + repo = "opam-repository"; + rev = "5c5a526ec9be1fdb631ef4104fad367ba8939bf3"; + sha256 = "1d8y2dn64814im6lmg3nvaqjd2rdjkwai3lsvlp4nggy324rk58c"; + }; + src = (pkgs.fetchFromGitHub) fetch; + }; + }; + selection = self.selection; +in +{ + format-version = 4; + ocaml-version = "4.12.0"; + repos = repos; + selection = + { + base-bytes = + { + opamInputs = + { + ocaml = selection.ocaml; + ocamlfind = selection.ocamlfind; + }; + opamSrc = repoPath (repos.opam-repository.src) + { + hash = "sha256:0a68lmbf68jgm1i3b59j2sc3ha9yhv4678f9mfwwvczw88prq7l3"; + package = "packages/base-bytes/base-bytes.base"; + }; + pname = "base-bytes"; + src = null; + version = "base"; + }; + base-threads = + { + opamInputs = { + }; + opamSrc = repoPath (repos.opam-repository.src) + { + hash = "sha256:1c4bpyh61ampjgk5yh3inrgcpf1z1xv0pshn54ycmpn4dyzv0p2x"; + package = "packages/base-threads/base-threads.base"; + }; + pname = "base-threads"; + src = null; + version = "base"; + }; + base-unix = + { + opamInputs = { + }; + opamSrc = repoPath (repos.opam-repository.src) + { + hash = "sha256:0mpsvb7684g723ylngryh15aqxg3blb7hgmq2fsqjyppr36iyzwg"; + package = "packages/base-unix/base-unix.base"; + }; + pname = "base-unix"; + src = null; + version = "base"; + }; + dune = + { + opamInputs = + { + base-threads = selection.base-threads; + base-unix = selection.base-unix; + ocaml = selection.ocaml or null; + ocamlfind-secondary = selection.ocamlfind-secondary or null; + }; + opamSrc = repoPath (repos.opam-repository.src) + { + hash = "sha256:0014dz25yn6m4b5f0m22jncy26ayq9v8zc7pq9rsg28ja1l4shrk"; + package = "packages/dune/dune.2.9.0"; + }; + pname = "dune"; + src = pkgs.fetchurl + { + sha256 = "07m476kgagpd6kzm3jq30yfxqspr2hychah0xfqs14z82zxpq8dv"; + url = "https://github.com/ocaml/dune/releases/download/2.9.0/dune-2.9.0.tbz"; + }; + version = "2.9.0"; + }; + ocaml = + { + opamInputs = + { + ocaml-base-compiler = selection.ocaml-base-compiler or null; + ocaml-config = selection.ocaml-config; + ocaml-system = selection.ocaml-system or null; + ocaml-variants = selection.ocaml-variants or null; + }; + opamSrc = repoPath (repos.opam-repository.src) + { + hash = "sha256:0xrq7j9zfynk524j69i3and0mqgi32wav751s4cqc1q7pqm47xpc"; + package = "packages/ocaml/ocaml.4.12.0"; + }; + pname = "ocaml"; + src = null; + version = "4.12.0"; + }; + ocaml-base-compiler = + { + opamInputs = { + }; + opamSrc = repoPath (repos.opam-repository.src) + { + hash = "sha256:0gf3z9qmi976x4iwndfslcim50ickla52x9fp94aqxrgvsy1ypn7"; + package = "packages/ocaml-base-compiler/ocaml-base-compiler.4.12.0"; + }; + pname = "ocaml-base-compiler"; + src = pkgs.fetchurl + { + sha256 = "0i37laikik5vwydw1cwygxd8xq2d6n35l20irgrh691njlwpmh5d"; + url = "https://github.com/ocaml/ocaml/archive/4.12.0.tar.gz"; + }; + version = "4.12.0"; + }; + ocaml-config = + { + opamInputs = + { + ocaml-base-compiler = selection.ocaml-base-compiler or null; + ocaml-system = selection.ocaml-system or null; + ocaml-variants = selection.ocaml-variants or null; + }; + opamSrc = repoPath (repos.opam-repository.src) + { + hash = "sha256:0h0hgqq9mbywvqygppfdc50gf9ss8a97l4dgsv3hszmzh6gglgrg"; + package = "packages/ocaml-config/ocaml-config.2"; + }; + pname = "ocaml-config"; + src = null; + version = "2"; + }; + ocamlfind = + { + opamInputs = + { + graphics = selection.graphics or null; + ocaml = selection.ocaml; + }; + opamSrc = repoPath (repos.opam-repository.src) + { + hash = "sha256:11avrzm0gdc6mz7dazr8q18ir5429ckc36s2mv0l8722znq8lc3k"; + package = "packages/ocamlfind/ocamlfind.1.9.1"; + }; + pname = "ocamlfind"; + src = pkgs.fetchurl + { + sha256 = "1qhgk25avmz4l4g47g8jvk0k1g9p9d5hbdrwpz2693a8ajyvhhib"; + url = "http://download.camlcity.org/download/findlib-1.9.1.tar.gz"; + }; + version = "1.9.1"; + }; + ounit = + { + opamInputs = + { + ocamlfind = selection.ocamlfind; + ounit2 = selection.ounit2; + }; + opamSrc = repoPath (repos.opam-repository.src) + { + hash = "sha256:19yrs98nq81hrdkgb3108a8bhkf8f9l7nm5pvb8f3k014cc3n3x2"; + package = "packages/ounit/ounit.2.2.4"; + }; + pname = "ounit"; + src = pkgs.fetchurl + { + sha256 = "0i9kiqbf2dp12c4qcvbn4abdpdp6h4g5z54ycsh0q8jpv6jnkh5m"; + url = "https://github.com/gildor478/ounit/releases/download/v2.2.4/ounit-v2.2.4.tbz"; + }; + version = "2.2.4"; + }; + ounit2 = + { + opamInputs = + { + base-bytes = selection.base-bytes; + base-unix = selection.base-unix; + dune = selection.dune; + ocaml = selection.ocaml; + stdlib-shims = selection.stdlib-shims; + }; + opamSrc = repoPath (repos.opam-repository.src) + { + hash = "sha256:1z5dlin5x6l5s7sbgkirsxgg00pr5l4gq7bdg2287kp4mlm5vgw0"; + package = "packages/ounit2/ounit2.2.2.4"; + }; + pname = "ounit2"; + src = pkgs.fetchurl + { + sha256 = "0i9kiqbf2dp12c4qcvbn4abdpdp6h4g5z54ycsh0q8jpv6jnkh5m"; + url = "https://github.com/gildor478/ounit/releases/download/v2.2.4/ounit-v2.2.4.tbz"; + }; + version = "2.2.4"; + }; + re = + { + opamInputs = + { + dune = selection.dune; + ocaml = selection.ocaml; + seq = selection.seq; + }; + opamSrc = "re.opam"; + pname = "re"; + src = self.directSrc "re"; + version = "development"; + }; + seq = + { + opamInputs = { + ocaml = selection.ocaml; + }; + opamSrc = repoPath (repos.opam-repository.src) + { + hash = "sha256:1vm8mk6zm2q3fwnkprl6jib048zr4ysldw0bl74x6wwbxj0vx6k9"; + package = "packages/seq/seq.base"; + }; + pname = "seq"; + src = null; + version = "base"; + }; + stdlib-shims = + { + opamInputs = + { + dune = selection.dune; + ocaml = selection.ocaml; + }; + opamSrc = repoPath (repos.opam-repository.src) + { + hash = "sha256:19g9dnaxyh2ajz6pdczdsqzzvsmfrxwx6f613inkr31jw5hrqkiz"; + package = "packages/stdlib-shims/stdlib-shims.0.3.0"; + }; + pname = "stdlib-shims"; + src = pkgs.fetchurl + { + sha256 = "0jnqsv6pqp5b5g7lcjwgd75zqqvcwcl5a32zi03zg1kvj79p5gxs"; + url = "https://github.com/ocaml/stdlib-shims/releases/download/0.3.0/stdlib-shims-0.3.0.tbz"; + }; + version = "0.3.0"; + }; + }; +} + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/nix/opam2nix.nix new/ocaml-re-1.10.3/nix/opam2nix.nix --- old/ocaml-re-1.9.0/nix/opam2nix.nix 1970-01-01 01:00:00.000000000 +0100 +++ new/ocaml-re-1.10.3/nix/opam2nix.nix 2021-09-13 21:26:15.000000000 +0200 @@ -0,0 +1 @@ +import (builtins.fetchTarball "https://github.com/timbertson/opam2nix/archive/v1.tar.gz") {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/re.opam new/ocaml-re-1.10.3/re.opam --- old/ocaml-re-1.9.0/re.opam 2019-04-06 09:05:39.000000000 +0200 +++ new/ocaml-re-1.10.3/re.opam 2021-09-13 21:26:15.000000000 +0200 @@ -21,7 +21,7 @@ depends: [ "ocaml" {>= "4.02"} - "dune" {build} + "dune" {>= "2.0"} "ounit" {with-test} "seq" ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ocaml-re-1.9.0/shell.nix new/ocaml-re-1.10.3/shell.nix --- old/ocaml-re-1.9.0/shell.nix 1970-01-01 01:00:00.000000000 +0100 +++ new/ocaml-re-1.10.3/shell.nix 2021-09-13 21:26:15.000000000 +0200 @@ -0,0 +1,17 @@ +let + pkgs = (import <nixpkgs> { }); + local = (import ./default.nix { }); + strings = pkgs.lib.strings; + inherit (pkgs) stdenv lib; +in with local; + +pkgs.mkShell { + inputsFrom = [ re ]; + buildInputs = (with pkgs; [ + gnumake + ocamlPackages.ocaml-lsp + ]) ++ (with opam; [ + # test + ounit + ]); +}