pax_global_header00006660000000000000000000000064134520477030014517gustar00rootroot0000000000000052 comment=42c7f8899c9b1a4e011053487a97cf7eab312d5f ocaml-re-1.9.0/000077500000000000000000000000001345204770300132255ustar00rootroot00000000000000ocaml-re-1.9.0/.gitignore000066400000000000000000000001361345204770300152150ustar00rootroot00000000000000.*.swp _build/ *.bak setup.data setup.log setup.exe *.native *.byte *.docdir .merlin *.installocaml-re-1.9.0/.travis.yml000066400000000000000000000005131345204770300153350ustar00rootroot00000000000000language: c sudo: required install: wget https://raw.githubusercontent.com/ocaml/ocaml-ci-scripts/master/.travis-opam.sh script: bash -ex .travis-opam.sh env: global: - PACKAGE=re matrix: - OCAML_VERSION=4.02 - OCAML_VERSION=4.03 - OCAML_VERSION=4.04 - OCAML_VERSION=4.05 - OCAML_VERSION=4.06 os: - linux - osx ocaml-re-1.9.0/CHANGES.md000066400000000000000000000067141345204770300146270ustar00rootroot000000000000001.9.0 (05-Apr-2019) ------------------- * Fix regression in `Re.exec_partial` (#164) * Mov gen related functions to `Re.Gen` and deprecate the old names (#167) * Introduce `Re.View` that exposes the internal representation (#163) 1.8.0 (04-Aug-2018) ------------------- * Fix index-out-of-bounds exception in Re.Perl.re (#160) * Add seq based iterators (#170) 1.7.3 (05-Mar-2018) ------------------- * Remove dependency on bytes package (#155) 1.7.2 (01-Mar-2018) ------------------- * Deprecate all Re_* modules. Re_x is now available as Re.X * Deprecate all re.x sub libraries. Those are all available as Re.X * Make all function in Re.Str tail recursive. 1.7.1 (19-Oct-2016) ------------------- * Fix Re_str.global_replace (#132) 1.7.0 (18-Sep-2016) ------------------- * Fix stack overflow in Re_str.full_split * Use correct exceptions in Re_str group functions * Add experimental Re.witness * Add experimental Re.Group.nb_groups 1.6.1 (20-Jun-2016) ------------------- * Fix Re.pp (#101) * Add Re.Group.pp (#102) 1.6.0 (30-May-2016) ------------------- * Add Re.pp and Re.pp_re (#55) * Fix ocamldoc syntax (#87) 1.5.0 (04-Jan-2016) ------------------- * Add Re.exec_opt. Like exec but doesn't raise * Add Group module. Old group accessors are deprecated. * Add Mark module * Improve docs of Re.repn * Improve docs of Re_pcre * Fix doc of Re_pcre.match * Consolidate variants of Re.glob that takes options to modify its behavior (?period, ?expand_braces). Old variants are deprecated. * New option ?pathname added for Re_glob.glob. Controls how the `/` character is matched 1.4.1 (06-Jun-2015) ------------------- * Fix 4.00.1 compatibilty with tests. 1.4.0 (12-May-2015) ------------------- * Add Re.{mark,marked,mark_set}. Regexps can now be "marked" to query post execution if they matched. 1.3.2 (14-Apr-2015) ------------------- * Fix replacing 0 length matches (#55) 1.3.1 (13-Mar-2015) ------------------- * Rename {Cset, Automata} to {Re_cset, Re_automata} 1.3.0 (02-Feb-2015) ------------------- * Add Re.split{,_gen,_token,_full,_full_gen} * Add Re.replace{,_string} * Add Re.all{,_gen} * Add posix classes of the form [:xxx:] * Add complement suport for posix classes * Add Multiline and anchored flag to Re_pcre * Add Re_pcre.full_split 1.2.2 (05-May-2014) ------------------- * Add a Re.whole_string convenience function to only match whole strings * Add a ?anchored parameter to functions in Re_glob to specify whole string matching * Document Re_glob module * Fix compilation of submatches occurring inside a Kleen star * Fix word boundary matching * Fix definition of Re.xdigit * Fix Re.exec_partial function * Fix compilation of patterns of the shape r1r2|r1r3 * Fixed compilation of re.cmxs (Vincent Bernardoff) * Improved matching of anchored regular expressions: stop as soon as we know there cannot possibly be any match. * Updated to OASIS 0.4.x (Vincent Bernardoff) * Add the linking exception to the license 1.2.1 (07-Apr-2013) ------------------- * Correct OASIS metadata (Christophe Troestler). * Fix typo in Invalid_arg error message (Jeremy Yallop). 1.2.0 (15-Jan-2012) ------------------- * Rename Pcre module to `Re_pcre` to make it more suitable for upstream packaging (it currently conflicts with the `Pcre` package). (Mehdi Dogguy). 1.1.0 (05-Sep-2012) ------------------- * Add a basic Pcre wrapper around Re_perl for porting applications using that API (Thomas Gazagnaire). 1.0.0 (01-Aug-2012) ------------------- * Initial public release. ocaml-re-1.9.0/LICENSE.md000066400000000000000000000655121345204770300146420ustar00rootroot00000000000000This Software is distributed under the terms of the GNU Lesser General Public License version 2.1 (included below), or (at your option) any later version. As a special exception to the GNU Library General Public License, you may link, statically or dynamically, a "work that uses the Library" with a publicly distributed version of the Library to produce an executable file containing portions of the Library, and distribute that executable file under terms of your choice, without any of the additional requirements listed in clause 6 of the GNU Library General Public License. By "a publicly distributed version of the Library", we mean either the unmodified Library, or a modified version of the Library that is distributed under the conditions defined in clause 3 of the GNU Library General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU Library General Public License. ---------------------------------------------------------------------- GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ocaml-re-1.9.0/Makefile000066400000000000000000000003671345204770300146730ustar00rootroot00000000000000DUNE ?= dune all: @$(DUNE) build test: @$(DUNE) runtest check: test clean: @$(DUNE) clean .PHONY: check test all clean .PHONY: all-supported-ocaml-versions all-supported-ocaml-versions: dune build @runtest --workspace dune-workspace.dev ocaml-re-1.9.0/README.md000066400000000000000000000055251345204770300145130ustar00rootroot00000000000000Description =========== Re is a regular expression library for OCaml. [![Build Status](https://travis-ci.org/ocaml/ocaml-re.svg?branch=master)](https://travis-ci.org/ocaml/ocaml-re) Contact ======= This library has been written by Jerome Vouillon (Jerome.Vouillon@pps.univ-paris-diderot.fr). It can be downloaded from Bug reports, suggestions and contributions are welcome. Features ======== The following styles of regular expressions are supported: - Perl-style regular expressions (module `Re.Perl`); - Posix extended regular expressions (module `Re.Posix`); - Emacs-style regular expressions (module `Re.Emacs`); - Shell-style file globbing (module `Re.Glob`). It is also possible to build regular expressions by combining simpler regular expressions (module `Re`). The most notable missing features are **back-references** and look-ahead/look-behind **assertions**. There is also a subset of the PCRE interface available in the `Re.Pcre` module. This makes it easier to port code from that library to Re minimal changes. Performances ============ The matches are performed by lazily building a DFA (deterministic finite automaton) from the regular expression. As a consequence, matching takes linear time in the length of the matched string. The compilation of patterns is slower than with libraries using back-tracking, such as PCRE. But, once a large enough part of the DFA is built, matching is extremely fast. Of course, for some combinations of regular expression and string, the part of the DFA that needs to be build is so large that this point is never reached, and matching will be slow. This is not expected to happen often in practice, and actually a lot of expressions that behaves badly with a backtracking implementation are very efficient with this implementation. The library is at the moment entirely written in OCaml. As a consequence, regular expression matching is much slower when the library is compiled to bytecode than when it is compiled to native code. Here are some timing results (Pentium III 500Mhz): * Scanning a 1Mb string containing only `a`s, except for the last character which is a `b`, searching for the pattern `aa?b` (repeated 100 times): - RE: 2.6s - PCRE: 68s * Regular expression example from http://www.bagley.org/~doug/shootout/ [1] - RE: 0.43s - PCRE: 3.68s [1] this page is no longer up but is available via the Internet Archive http://web.archive.org/web/20010429190941/http://www.bagley.org/~doug/shootout/bench/regexmatch/ * The large regular expression (about 2000 characters long) that Unison uses with my preference file to decide whether a file should be ignored or not. This expression is matched against a filename about 20000 times. - RE: 0.31s - PCRE: 3.7s However, RE is only faster than PCRE when there are more than about 300 filenames. ocaml-re-1.9.0/TODO.txt000066400000000000000000000046531345204770300145430ustar00rootroot00000000000000* To compile r{i,j} we need a sequence that does not match epsilon (or a constructor around an expression telling that this expression does not match epsilon) * A subexpression repeated by an asterisk ( '*' ) or an interval expression shall not match a null expression unless this is the only match for the repetition or it is necessary to satisfy the exact or minimum number of occurrences for the interval expression. * There might be a typo in deriv_1/delta_1: should we generate 'TMatch mark' or 'TMatch mark'? (neither is correct!) POSIX: "(a?)*" "b" "" "(a?)*" "ab" "a" "((a)|(b))*" "ab" -> "b" none "b" Str "(a?)*" "b" no submatch "(a?)*" "ab" "a" "((a)|(b))*" "ab" -> "b" "a" "b" Javascript "(a?)*" "b" no submatch "(a?)*" "ab" "a" "((a)|(b))*" "ab" -> "b" none "b" PCRE "(a?)*" "b" "" "(a?)*" "ab" "" "(a?)*?" "b" "" "(a?)*?" "ab" "a" "((a)|(b))*" "ab" -> "b" "a" "b" Emacs "(a?)*" "b" "" "(a?)*" "ab" "" "(a?)*?" "b" "" "(a?)*?" "ab" "a" "((a)|(b))*" "ab" -> "b" "a" "b" r{0,0} = eps r{i+1,j+1} = r,r{i,j} r{0,j+1} = r,r{0,j} | eps PCRE/Emacs r{0,j+1} = (r-eps},r{0,j} | eps JavaScript * Rewrite sequences of sequences when possible... High priority ============= * Improve the Perl regular expressions parser * Character classes (in the three regular expression parsers) * Reduce memory usage - More compact representation of character sequences - Special notation for "anything but this set of characters" (more generally, optimize the compilation of regular expressions) * Simple optimisations - alt containing alt - epsilon elimination - Seq (Seq (x,y), z) => Seq (x, Seq (y, z)) under some circumstances (x or y has a fixed length) ... * Test suite Medium priority =============== * Implement back-references * Implement look-ahead and look-behind assertions Low priority ============ * Optimize the main loop for processor that are not register starved * Rewrite the main loops in C (but keep the option to compile a pure OCaml version) * Limit the size of the cached DFAs by removing states that have not been used recently * Documentation Other ideas =========== * It would be great to have a more generic interface (parameterized over some abstract tokens). * Compile checked printers parameterized over match groups (DRY for literal subexpressions) ocaml-re-1.9.0/benchmarks/000077500000000000000000000000001345204770300153425ustar00rootroot00000000000000ocaml-re-1.9.0/benchmarks/.merlin000066400000000000000000000000471345204770300166320ustar00rootroot00000000000000S ../lib B ../_build/** PKG core_bench ocaml-re-1.9.0/benchmarks/benchmark.ml000066400000000000000000000106471345204770300176360ustar00rootroot00000000000000open Core.Std open Core_bench.Std module Http = struct open Re let space = rep blank let crlf = str "\r\n" let token = rep1 @@ compl [ rg '\000' '\031' ; set "\127)(<>@,;:\\/[]?={}" ] let meth = token let version = let digits = rep1 digit in let decimal = seq [digits ; opt (seq [char '.' ; digits])] in seq [str "HTTP/" ; decimal] let uri = rep1 (compl [char '\n']) let request_line = [ space ; group meth ; space ; group uri ; group version ; space] |> seq let header = let key = group (rep1 (Re.compl [char ':'])) in let value = group (rep1 (Re.compl [char '\n'])) in seq [space ; key ; space ; char ':' ; space ; value ; space ; crlf] let request' = seq [request_line ; crlf ; rep header ; crlf ] module Export = struct let request = request' let request_g = request' |> no_group let requests = request' |> rep1 let requests_g = request' |> no_group |> rep1 end end let http_requests = In_channel.read_all "benchmarks/http-requests.txt" let str_20_zeroes = String.make 20 '0' let re_20_zeroes = Re.(str str_20_zeroes) let tex_ignore_re = "benchmarks/tex.gitignore" |> In_channel.read_lines |> List.map ~f:(fun s -> match String.lsplit2 s ~on:'#' with | Some (pattern, _comment) -> pattern | None -> s) |> List.filter_map ~f:(fun s -> match String.strip s with | "" -> None | s -> Some s) |> List.map ~f:Re_glob.glob |> Re.alt let tex_ignore_filesnames = In_channel.read_lines "benchmarks/files" let lots_of_a's = String.init 101 ~f:(function | 100 -> 'b' | _ -> 'a') let lots_o_a's_re = Re.(seq [char 'a' ; opt (char 'a') ; char 'b']) let media_type_re = let re = Re.Emacs.re ~case:true "[ \t]*\\([^ \t;]+\\)" in Re.(seq ([start; re])) (* Taken from https://github.com/rgrinberg/ocaml-uri/blob/903ef1010f9808d6f3f6d9c1fe4b4eabbd76082d/lib/uri.ml*) let uri_reference = Re_posix.re "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?" let uris = [ "https://google.com" ; "http://yahoo.com/xxx/yyy?query=param&one=two" ; "file:/random_crap" ] let benchmarks = [ "20 zeroes", re_20_zeroes, [str_20_zeroes] ; "lots of a's", lots_o_a's_re, [lots_of_a's] ; "media type match", media_type_re, [" foo/bar ; charset=UTF-8"] ; "uri", uri_reference, uris ] let exec_bench exec name (re : Re.t) cases = let re = Re.compile re in Bench.Test.create_group ~name ( List.mapi cases ~f:(fun i case -> let name = sprintf "case %i" i in Bench.Test.create ~name (fun () -> ignore (exec re case)) ) ) let exec_bench_many exec name re cases = let re = Re.compile re in Bench.Test.create ~name (fun () -> cases |> List.iter ~f:(fun x -> ignore (exec re x)) ) let rec read_all_http pos re reqs = if pos >= String.length reqs then () else let g = Re.exec ~pos re reqs in let (_, pos) = Re.Group.offset g 0 in read_all_http (pos + 1) re reqs let rec drain_gen gen = match gen () with | None -> () | Some _ -> drain_gen gen let benchmarks = let benches = benchmarks |> List.map ~f:(fun (name, re, cases) -> Bench.Test.create_group ~name [ exec_bench Re.exec "exec" re cases ; exec_bench Re.execp "execp" re cases ; exec_bench Re.exec_opt "exec_opt" re cases ] ) in let http_benches = let open Bench in let open Http.Export in let manual = [ request, "no group" ; request_g, "group" ] |> List.map ~f:(fun (re, name) -> let re = Re.compile re in Test.create ~name (fun () -> read_all_http 0 re http_requests) ) |> Test.create_group ~name:"manual" in let many = let requests = Re.compile requests in let requests_g = Re.compile requests_g in [ Test.create ~name:"execp no group" (fun () -> ignore (Re.execp requests http_requests) ) ; Test.create ~name:"all_gen group" (fun () -> http_requests |> Re.all_gen requests_g |> drain_gen ) ] |> Test.create_group ~name:"auto" in Test.create_group ~name:"http" [manual ; many] in benches @ [ [ exec_bench_many Re.execp "execp" ; exec_bench_many Re.exec_opt "exec_opt" ] |> List.map ~f:(fun f -> f tex_ignore_re tex_ignore_filesnames) |> Bench.Test.create_group ~name:"tex gitignore" ] @ [http_benches] let () = Command.run (Bench.make_command benchmarks) ocaml-re-1.9.0/benchmarks/dune000066400000000000000000000001021345204770300162110ustar00rootroot00000000000000(executable (libraries re threads core_bench) (name benchmark)) ocaml-re-1.9.0/benchmarks/files000066400000000000000000001203641345204770300163750ustar00rootroot00000000000000./.merlin ./re_match.native ./lib ./lib/re-api.odocl ./lib/re_glob.mllib ./lib/re.mli ./lib/re_cset.ml ./lib/re_automata.ml ./lib/re.ml ./lib/re_emacs.mli ./lib/re_glob.mldylib ./lib/re_pcre.mli ./lib/re_perl.mldylib ./lib/re_posix.mli ./lib/re_perl.mli ./lib/re.mldylib ./lib/re_posix.mldylib ./lib/re_automata.mli ./lib/re_glob.ml ./lib/re_emacs.ml ./lib/re_pcre.mllib ./lib/re_glob.mli ./lib/re_str.mldylib ./lib/re.mllib ./lib/re_posix.mllib ./lib/re_pcre.ml ./lib/re_emacs.mldylib ./lib/META ./lib/re_pcre.mldylib ./lib/re_cset.mli ./lib/re_emacs.mllib ./lib/re_str.mli ./lib/re_perl.ml ./lib/re_fmt.ml ./lib/re_perl.mllib ./lib/re_posix.ml ./lib/re_str.ml ./lib/re_str.mllib ./lib_test ./lib_test/test_easy.ml ./lib_test/test_emacs.ml ./lib_test/re_match.ml ./lib_test/longest.c ./lib_test/pcre_match.ml ./lib_test/.cvsignore ./lib_test/test_glob.ml ./lib_test/fort_unit.mllib ./lib_test/test_perl.ml ./lib_test/fort_unit.ml ./lib_test/test_exec_iter.ml ./lib_test/perl_scan.pl ./lib_test/Input ./lib_test/scan.ml ./lib_test/fort_unit.mldylib ./lib_test/unison2.ml ./lib_test/META ./lib_test/unison.ml ./lib_test/test_pcre.ml ./lib_test/glob.ml ./lib_test/pcre_scan.ml ./lib_test/re_scan.ml ./lib_test/Makefile ./lib_test/test_str.ml ./lib_test/test_re.ml ./lib_test/unison3.ml ./setup.exe ./_oasis ./repl.ml ./test_perl.native ./setup.data ./test_re.native ./setup.ml ./benchmarks ./benchmarks/.merlin ./benchmarks/benchmark.ml ./benchmarks/.#files ./benchmarks/.#tex.gitignore ./.gitignore ./.git ./.git/COMMIT_EDITMSG ./.git/objects ./.git/objects/bd ./.git/objects/bd/7b4a58cc13ca497618e5f8eaa664727a489c14 ./.git/objects/04 ./.git/objects/04/a2c275e68174559191e1f03369472ab6cc79a6 ./.git/objects/04/266b2bfdc3cb6dd1557ddc6cca27dd1c2483de ./.git/objects/c3 ./.git/objects/c3/b0f3506b6efa82e7d8455a51c40f674e362019 ./.git/objects/ae ./.git/objects/ae/edba64f100def873a670083e7cc4dec013b461 ./.git/objects/ae/e951b55c41573ce87f3e1e9ed7af59cfd03465 ./.git/objects/ae/6fb476af3ed0c1c09bac3cca8825a1983f6baf ./.git/objects/80 ./.git/objects/80/c9e3062a7a04de5f4fac4e99402caa9b51a06a ./.git/objects/80/c8e9cfeb808e093b68db94016ed90c821111f7 ./.git/objects/pack ./.git/objects/pack/pack-866532c1406fa054e3eb4a18c69f02811d0d9218.pack ./.git/objects/pack/pack-866532c1406fa054e3eb4a18c69f02811d0d9218.idx ./.git/objects/ed ./.git/objects/ed/0f521c10cf8d6bff59836ec4ccbe7e5457833b ./.git/objects/7a ./.git/objects/7a/93d826a964cfcda511666ea90cae1c932fa420 ./.git/objects/7a/948d869ac1991341c6a809fff33fe6f7578176 ./.git/objects/7a/11dea700ff573997fa79ee6d720d8c36bb8c24 ./.git/objects/57 ./.git/objects/57/41501919c83c417773c4db93c40f064c01b9fa ./.git/objects/57/5df2075ef86ab5052cf3f640cfef0ade065079 ./.git/objects/c1 ./.git/objects/c1/b86cbaa2bc74068aa01996d5361165488ad90b ./.git/objects/d5 ./.git/objects/d5/fae05fd2c4e4319d1d8b72b47c5bf7c5c988bc ./.git/objects/d5/a493ad0448a01ef3b090cafa65e4052e3e3443 ./.git/objects/d5/18889bb8e29093ac8c151dbfb94ecdb55da37b ./.git/objects/c0 ./.git/objects/c0/3edfcb9c4d1ba4d5c714784719f2babc0d4bc2 ./.git/objects/ea ./.git/objects/ea/59fc8cae70bc30d4925b5d754d3eaa4c86fbe7 ./.git/objects/ea/96d0c79a09edde6fb5fdca45fad5eeb6b94a3b ./.git/objects/ea/d533485541976b0e8651823b48dd3b893fd7bf ./.git/objects/bf ./.git/objects/bf/9238d7470f96c20ef3b8ae9ae800c29a24b7d0 ./.git/objects/da ./.git/objects/da/5d5f8e2a5adf35ea1918972f87bae5ef20eba8 ./.git/objects/da/9d6c16f47466f0483a426802c81a4e2f105565 ./.git/objects/5d ./.git/objects/5d/68a2c24d022272086e02e201a34a7cc471a810 ./.git/objects/d1 ./.git/objects/d1/baa7c6cb5a197c2fa16d74d015cb65383befae ./.git/objects/d1/4a2f9a73098a607be995953a176a4c158eda31 ./.git/objects/a8 ./.git/objects/a8/385bd4963671a9f8e46367258ed74470230be8 ./.git/objects/a8/88411f7ae15f92b0a4f115b6a198bb9fca17eb ./.git/objects/a8/6354c21c4ea14488a7749ce9ca7319dfd7962d ./.git/objects/f8 ./.git/objects/f8/402f7182db519f40022913d9b7f545155e23da ./.git/objects/f8/fe27353f98e6449f9c140ed285c66111a83c8a ./.git/objects/32 ./.git/objects/32/7e89b0ce8c6c488a6052e2de5204ef89e2f507 ./.git/objects/32/46e88c270717153eee687e584c48c2b7611500 ./.git/objects/d3 ./.git/objects/d3/4bab001c846b49c144845ae06905122fc00d5b ./.git/objects/d3/14cca150738f34ec06d0a620746fa4b664d488 ./.git/objects/d3/c1b11ad75157f9b7976205c02c5017edbe91e5 ./.git/objects/7c ./.git/objects/7c/4fff7192504e558898de1a0a6a03f40b1ba383 ./.git/objects/7c/ca263ea8cf851ed5e6b620b1ac975a52cd1ab9 ./.git/objects/7c/c8bf775e67bee805e45e2c2de7292c060f31ce ./.git/objects/e3 ./.git/objects/e3/fee6d0fba12db992dab0c59f0c0af51e00f0cc ./.git/objects/73 ./.git/objects/73/e55a4522cb6094dbfa5259ea1246a80e3b8c40 ./.git/objects/73/7cc095a1c47d9895cf38d27633f8fde7024868 ./.git/objects/73/afa2a0065c795b73f8ac64879d85342765624a ./.git/objects/48 ./.git/objects/48/85f690a7e2bbf6c95ab017ebeddf13d4adbf01 ./.git/objects/48/a13cb1beef406dd4a4e2306e1e37f6836e4825 ./.git/objects/8c ./.git/objects/8c/a9e8d133eef4f47c05922233619de5a86ee4ab ./.git/objects/8c/df1c29071e45af80bf897cac73b4c1566e2d50 ./.git/objects/1b ./.git/objects/1b/9d5c43861498c1854465ac03e76a514d5cbaa8 ./.git/objects/50 ./.git/objects/50/ef8ba0f5817ad270ae921fea07bb8797b9c267 ./.git/objects/50/48505dcfbfd75f4bbad53bf5d71105215052c7 ./.git/objects/eb ./.git/objects/eb/31ab22a61ecfba506504fdf4b0f5cd28af2e11 ./.git/objects/eb/bf41561fdfffa8b973ad8c8d60c00907c59571 ./.git/objects/eb/dbd748cd4c6e3fcadd5087b9508a20a34c8125 ./.git/objects/ef ./.git/objects/ef/5f4e84fc1fb16d0e6a3b6402b2ef7b4ed4597f ./.git/objects/ca ./.git/objects/ca/67f392b19172f6bc90132ef568aeadff4c47e4 ./.git/objects/ca/9cd9a973452dcedfabe0bb1ee39eaa825856b7 ./.git/objects/ca/0249ae201624a0915b20a04f0bea1e88fbac12 ./.git/objects/c5 ./.git/objects/c5/531af344c2046d8887b5a8414fca0034be08c4 ./.git/objects/c5/c32cce665964562c01cb70dbd1d931d0fc9013 ./.git/objects/c5/dd991dc612c5cd22a26633a5ab5cb1e19065c3 ./.git/objects/75 ./.git/objects/75/c564016f8ebf5726272c3f624f8f607002bbda ./.git/objects/4e ./.git/objects/4e/f45ea3fd278fb84e61bb004f62beeb6e58a461 ./.git/objects/4e/af84d38158ff6aeab975f4b93bca267185ff75 ./.git/objects/cb ./.git/objects/cb/a0873bb0fb8cdd095efea7fc00d244d9f33dd6 ./.git/objects/6a ./.git/objects/6a/00cd81ccdbe607f9585878296c1e1e2c5b7cbd ./.git/objects/6a/93ab65f245de47a5a6c97f6b95e2b5ed93c6ce ./.git/objects/6a/521ac0a70a030b4570b17ce369ae7e0ccb5bcc ./.git/objects/6a/00c91ef0a06a2aa19cfb94ba06503cb1d0a2c5 ./.git/objects/e8 ./.git/objects/e8/4dc23cd8d2b83c0986002851ad228ca86f104b ./.git/objects/e8/ad3cd2087d55ff7928f7ad191a5c447a86a253 ./.git/objects/06 ./.git/objects/06/1a15896701e0696b9056e8c1f3ed0602b696c7 ./.git/objects/06/8886279674c32c6c0189ca0eb9ca3427b6a73f ./.git/objects/06/96d3afa20ddbad8c4e09ffc80da6a062ecca0f ./.git/objects/26 ./.git/objects/26/d94482417d0415bc3074d578ea15fa29bf61eb ./.git/objects/51 ./.git/objects/51/21ef81a3c018e7ece82b8fa53804f49b187e61 ./.git/objects/51/7475c493f88584541456158468830c728a385f ./.git/objects/f7 ./.git/objects/f7/e5d4ab3ab0b9b806b17f166db3de7cb83e16ba ./.git/objects/49 ./.git/objects/49/b13c62775b3f1ae207c1c7b937b8799d280a53 ./.git/objects/49/9613067efd80e477704c5752e2e24d16b685e5 ./.git/objects/e7 ./.git/objects/e7/71a89a26f22e59b14d4537f341206ae7e2dd59 ./.git/objects/5c ./.git/objects/5c/28f300f108705b0838519b16b64040e1753dac ./.git/objects/7d ./.git/objects/7d/24c5c18d327f576162279ec5c8d1040ae9f53a ./.git/objects/d0 ./.git/objects/d0/bdcf3a2e68cf891369b37c0bdafe5b3a8c3721 ./.git/objects/ad ./.git/objects/ad/dc2932430682c6f4aebf981bbdb60bd8650a46 ./.git/objects/5e ./.git/objects/5e/5a6c6e318cbcc56ac17c785e42512984a54ffe ./.git/objects/5e/65dfb3785145e3359094f2da9a9308ca89f95a ./.git/objects/5e/e61c21b52ad286753d76024e686ae2188f3d9c ./.git/objects/5e/7211f1f557ceea2922e95c9353344a7d8011eb ./.git/objects/60 ./.git/objects/60/825f155344cfac612ddb9aa4056cee1a3758fa ./.git/objects/60/df4d354a7d252d34d31d266064a498bae0c00e ./.git/objects/60/9434044eb5c63cfbe323346a76c37316f5d3cb ./.git/objects/68 ./.git/objects/68/7f8ea68a53e8a91694db6e8e19309c7aaff242 ./.git/objects/68/5de33ed341bc2e51a650f5c42f02a4cea86c74 ./.git/objects/68/ba3add2e2f20ff74ca504aa69a067269748796 ./.git/objects/68/54eba89564df3120ae33bd3905f70af0a9508e ./.git/objects/bb ./.git/objects/bb/26307254872961f81864ae695a2212da53e305 ./.git/objects/bb/0b632d318e1cc55446ab86264a943dc662dedf ./.git/objects/bb/04232d06b8b1b51d0313c76ecdf53fbb38b133 ./.git/objects/79 ./.git/objects/79/05fb61e4f1057e53188709c091739c2adabdce ./.git/objects/3b ./.git/objects/3b/6969415623e49b583fd9623a21269d16cf67d8 ./.git/objects/3b/a8e873cae0cd0d76051c8845a05ee7e5d6d2d1 ./.git/objects/24 ./.git/objects/24/18f0e1209770aeeb848a83fab8a87a5e9a3a86 ./.git/objects/24/4d94f9094fe4b391a781a7b5059d19233558c0 ./.git/objects/1a ./.git/objects/1a/a9a109bfb5e0100583062628741d37edbef198 ./.git/objects/cf ./.git/objects/cf/b4058d5efe88c7e11216de67c3ddecfaeb74c1 ./.git/objects/cf/ca9f3ec8ffd3a716e84a1816fd2f290aff45f3 ./.git/objects/cf/249dc6bf90a05272ea34a37c179695ec1679e8 ./.git/objects/41 ./.git/objects/41/7e9c7be145d7ce950e2634e24bdb7ead9eaf27 ./.git/objects/e0 ./.git/objects/e0/cf46969ea651e5939b9d5f048eaec3ec1de4c2 ./.git/objects/e0/56cae16e516031cd82e2190a7a021a95145026 ./.git/objects/e0/897837a3548051e45ac861ab417adf7c59829f ./.git/objects/e0/d97cc471e24acd66068a44308c7abff19b1925 ./.git/objects/91 ./.git/objects/91/a4117c6026321105e7a694173a05b2644d77c2 ./.git/objects/91/b1cee3be1539bb24a359d20d8a5e076a9cf30d ./.git/objects/fa ./.git/objects/fa/eb7cd164e1c586e7d45a09e0619cf9a74f54af ./.git/objects/fa/8e7262e1a26131ac68a1a911baca583f27dca4 ./.git/objects/fa/9de6a7c9f2dee85a1145e1fc4c5d1b570e964b ./.git/objects/2b ./.git/objects/2b/4c9ad40ba8fde41829a22e88bd26d38cd513f9 ./.git/objects/54 ./.git/objects/54/f717fa1d49e761b89e8f8097e8e3afde5cc6f7 ./.git/objects/54/f513d93e0e3263265c24591a7c874b53030436 ./.git/objects/b4 ./.git/objects/b4/6ae8881ee452f7a4ff0efb75bac923f36d14aa ./.git/objects/b4/8ffdfbe33be1dfd1783c8ff6b1e8fbe41db10d ./.git/objects/b4/e29997072acf52d882cfced7e85bb3b37460b5 ./.git/objects/b4/25a61759c2334ae65b46e56533f54804906c7a ./.git/objects/ac ./.git/objects/ac/1468dfa7da0b2fea46f17a3525c19feacdc1a1 ./.git/objects/ac/375885c60a0ea3a99d8bb439109c1fa895761d ./.git/objects/ac/fe49dc5da96f42f02493db63c143e2e2babad1 ./.git/objects/ac/6c0f696722f17907f137f4c7fad91e64f49dac ./.git/objects/e9 ./.git/objects/e9/cc98781f3762e4dd7e8be3b025723674999a31 ./.git/objects/1e ./.git/objects/1e/08112d5532b7b52a6d51270e73b5bf019ebd0a ./.git/objects/6c ./.git/objects/6c/e4e9093f07b21a48bb122f10a347e38eac84a3 ./.git/objects/03 ./.git/objects/03/fb2ad72c7a8427949a2bd42155098c7ba5292b ./.git/objects/b5 ./.git/objects/b5/3290a08b842bb02ec8b9a453ddcce593595285 ./.git/objects/1f ./.git/objects/1f/b018c263111f5612dff4a0714d133fa14b47d0 ./.git/objects/f5 ./.git/objects/f5/5fa50d15939fef068814d393f10c47d6c24df0 ./.git/objects/78 ./.git/objects/78/c2eef20df32f85b780af9ea5cda026a0c597ec ./.git/objects/05 ./.git/objects/05/c94e09c13c59b6b0313c670a3b2b05f104e9d5 ./.git/objects/05/6aa0e5511235422238f4944ab543c1339ba472 ./.git/objects/05/2233649e450bb03b929975139eeb624310852e ./.git/objects/05/0ac4c6759899cd6c1c48d74aaa8cdeb8802d67 ./.git/objects/05/5c86781ebb8d7466e996d2a953ffb2701160b7 ./.git/objects/3a ./.git/objects/3a/b09d8cd602c91f6b13418aedfc10c6dea50311 ./.git/objects/3a/0080d9bd9df6701481c73c108df8f8aba270d6 ./.git/objects/3f ./.git/objects/3f/121aca11150765ad412e552c38cb846cdf1b25 ./.git/objects/9d ./.git/objects/9d/c192d47b5c60f58ea01b6fbb3cac7f95355920 ./.git/objects/dc ./.git/objects/dc/81451f732d8886a46ba4be0eb8689c3ffa05ff ./.git/objects/dc/277721b85d2c24888d9b295d73e77dc0b56c47 ./.git/objects/11 ./.git/objects/11/f3056a841ad601f309f9bb45fd1e7a45bdc35a ./.git/objects/09 ./.git/objects/09/83adb85f1e3af304b3219d112d87868940bd34 ./.git/objects/09/9d1ab30c98206fe2cd21e5351e4e739ddca093 ./.git/objects/a6 ./.git/objects/a6/78884c9d14735ad62e6ffe8edeb237b153b31f ./.git/objects/90 ./.git/objects/90/d315297656082d1d3fa42398237e6fd7ca8b77 ./.git/objects/90/131c7cf785f05180b94d3fa03ea5a15bc3fc86 ./.git/objects/9c ./.git/objects/9c/5bef9eb738539b7ef600afb5e4a4daf520ecf3 ./.git/objects/9c/5e872385933c0748afbe0d04721d2d87fcef7a ./.git/objects/9e ./.git/objects/9e/967e175d46284466def0287af70684002ebc9b ./.git/objects/98 ./.git/objects/98/2ac64fcb212641da96dd4aeba1c4d3a2089c8d ./.git/objects/83 ./.git/objects/83/c7ca0b3a62936df5bdadf81866f2f42a60201d ./.git/objects/ee ./.git/objects/ee/905700bdc10dd27f0b9b5d3e8e7c63cdb003a8 ./.git/objects/ee/137eb490291da49905c526776f3240dd994bde ./.git/objects/8b ./.git/objects/8b/b979b870b98d1421703d3c5f9b4506b34da31b ./.git/objects/8b/94333973de20dc2f9f6fba276d77957a585f19 ./.git/objects/8b/49a1a69ac34a2a9133ff3cfb2b30d7ce21269c ./.git/objects/cd ./.git/objects/cd/149e97dcb42e9893f15b0908cc6e7be8c176ad ./.git/objects/f3 ./.git/objects/f3/ff42162b9ceaa17323e15da2fcae4455acdc94 ./.git/objects/df ./.git/objects/df/0cad1cb3e9fa09265d3f63deedc382639dd902 ./.git/objects/74 ./.git/objects/74/3d2df4b1818f0aa743f57a85a4a5fb41b01fa9 ./.git/objects/74/01fc63e34bb3750d5b16c5d151653c8d6cfbc0 ./.git/objects/01 ./.git/objects/01/2e7dc0ac588f0e708ee8a8d115dc7c064c12b7 ./.git/objects/01/b09c53d179d687bc0837662bc48601e928502e ./.git/objects/01/7b3e99b3434bfe6ef2edb0a75b080311844169 ./.git/objects/dd ./.git/objects/dd/ad7182883890236f925f3353f4873c0b75034a ./.git/objects/18 ./.git/objects/18/8fe3d25861b14cd4af1163410b61f73ca4a04e ./.git/objects/62 ./.git/objects/62/064f59de8e93a5664bf43829e477bd9985cef6 ./.git/objects/2f ./.git/objects/2f/cd5c7dea3df5fa12fcbb5f26c8582b2910c447 ./.git/objects/b6 ./.git/objects/b6/8cc01c492b43223b504821bfd73b4f583ef4e2 ./.git/objects/be ./.git/objects/be/6b86d77fbb51906eacba3df56274612f1c3029 ./.git/objects/be/0938c18155c11f355d0fdc81c489c599cde3a7 ./.git/objects/be/d2ef86152fa9a0aabd84027e317733f0dfbae7 ./.git/objects/be/f110dd4cfaa19684396aaf93b27a5fb3c0b945 ./.git/objects/f6 ./.git/objects/f6/354b6caad8336c77feff4de8509c274a27fb70 ./.git/objects/21 ./.git/objects/21/5eb4b90109c24b08014bba985aa654feb57c59 ./.git/objects/f2 ./.git/objects/f2/687c378697490c59291d1cec912fe66852453a ./.git/objects/f2/d72115d8389718be364c28fc13785e5277b180 ./.git/objects/3d ./.git/objects/3d/a02568239608f630e802f4dd777449d0913e03 ./.git/objects/1d ./.git/objects/1d/2143cfb7d3376ecd5486c18c779c9d144d384c ./.git/objects/6f ./.git/objects/6f/5fb29affd8ac04ecf3574d5e99a716b414f2ca ./.git/objects/6f/6df7bced1281095533e756c0d6b9e7373f1a8b ./.git/objects/6f/52a7ca4ac7a38e8705299c2d9473ca1058b627 ./.git/objects/45 ./.git/objects/45/f68c1233212098478ac83525e9e68e2df1fadb ./.git/objects/45/6f776946d4828283ba374a165742234590fcc9 ./.git/objects/45/7aca0b40cef66eacf359630f145a4ff26364f2 ./.git/objects/5a ./.git/objects/5a/de07472965b3a18ce368b40dc9c904278142b9 ./.git/objects/info ./.git/objects/af ./.git/objects/af/f436ea457490f0752d934983bf1bbba2e2197a ./.git/objects/af/45c22cb2b534b5698562b3080e747fefa1b981 ./.git/objects/d8 ./.git/objects/d8/f83208765b69ade21aa13ffcdd38648bc54f14 ./.git/objects/70 ./.git/objects/70/e2c3dfaef29f8c8a3fa5d714105d3f5c3cd10f ./.git/objects/70/d74188dd90fb7e09d2d163dfa874e7c9e434bd ./.git/objects/61 ./.git/objects/61/a4c4b922c4ef41400d990031f3ac12f6a0888c ./.git/objects/61/6f06980312fc46031d9f21f29beef5e17d46f1 ./.git/objects/61/21078331176aaee1238c0f059f7f94663690b3 ./.git/objects/61/b65d28779937e8010a8c9d5f7eeeddbc5e0294 ./.git/objects/84 ./.git/objects/84/6ed3f02af5b46751dc2b0ff84690a84abf8f52 ./.git/objects/84/4378673c7db10ddc3e8d22a8187ebbc8905030 ./.git/objects/23 ./.git/objects/23/f56c7122758ebed362f40e98d4f6030659abb4 ./.git/objects/23/52ab57fcf2e8a26f2bf625baf5b5bbfb831417 ./.git/objects/23/b7b897cff7f35ae6566ce97c6c7c2590df15f2 ./.git/objects/23/cb216300bc481ca8915b935e563f4d409199e1 ./.git/objects/db ./.git/objects/db/06339ac988ad5c24e59b1e72038c9bc8dcc4d7 ./.git/objects/db/1f143eeac8eeb55f3ef826718e1d6f915cc5f8 ./.git/objects/f4 ./.git/objects/f4/427b4d63bf1508f56f365c65e85280d1af5763 ./.git/objects/f4/a591498b21a52c805a11509178fa5d0915f526 ./.git/objects/f4/0c870089b85b6402c0a2243f740a1370c79286 ./.git/objects/0e ./.git/objects/0e/189b2485f4535994863ca52a6420ec623f819d ./.git/objects/0e/e9b8159d8b6e430b82845f790cb54669e833f3 ./.git/objects/0e/e16c90707c76e59789d809ab5fc41fc91f5f67 ./.git/objects/0e/9d4bcf8f359d586197ff7e48bfb2662c0c0935 ./.git/objects/d2 ./.git/objects/d2/00c42d909a31c17dea48da932202860b406cf9 ./.git/objects/d2/b9537b66981e8063b93ac516098a9ab07a531b ./.git/objects/2d ./.git/objects/2d/45d0f37ab6828e8531fbf86096bc9d8e895527 ./.git/objects/2d/99122bb3539025961f0fda6ae664b7342b6b83 ./.git/objects/2d/1e8b892f7ee580e10244ba83ac6cc89e7ba727 ./.git/objects/2d/4b717bf8427170e5906538104c6d0fa4d630f0 ./.git/objects/82 ./.git/objects/82/56665942d2d563c29a09c8e8dd633014b4514b ./.git/objects/82/08d67320a0aff6533a4b7fac917ddc79f95418 ./.git/objects/82/69e1621ff5621db953bb1e5c26ccc9141eb8b3 ./.git/objects/0d ./.git/objects/0d/6a0b5fe6a1bafad0544e22510df8a62335a609 ./.git/objects/0d/36a5901973e607b333be7b03ba47eea66dc403 ./.git/objects/0d/42bacc3191f370f0f4bc276cd908061f9ac828 ./.git/objects/0d/707ecbb8abf68b3ebfb525b63937f9c805cef1 ./.git/objects/10 ./.git/objects/10/48a1a8ae5742d323ae648c92a777d1d2d2015b ./.git/objects/59 ./.git/objects/59/151f39243bb30f51e9dc7595311d93103d6eb4 ./.git/objects/63 ./.git/objects/63/9f63c06b29f39840edd73ad04cd3b8309204f0 ./.git/objects/63/2775a8aa713d331205fa1d8c167e84ad9186cb ./.git/objects/5b ./.git/objects/5b/52231d17726d4ad4ea7994fe105eb81e9e9dd9 ./.git/objects/14 ./.git/objects/14/36d8a33498d27fa02e0f2e3c8862475bfacebd ./.git/objects/17 ./.git/objects/17/662c8875023c93144ae394f2c76c8c3cda38a0 ./.git/objects/17/54196f5997eef681179aedae446349ea1b8f95 ./.git/objects/3e ./.git/objects/3e/997e9b6647df287339fcde654c42aa30505be4 ./.git/objects/3e/cc46e96a32867bbe05b2290fc126ab93f85bcd ./.git/objects/56 ./.git/objects/56/fd5d33c9c2bfaa8805dc058d7fde9152723a33 ./.git/objects/56/f541e80ea129e6e064f8b43cacacb70e17953e ./.git/objects/bc ./.git/objects/bc/1bf84bbb65652f4b787dd7b446860a32c2e8ca ./.git/objects/bc/82b6b7fbd83ed55e18d675745ba2efb6239f5b ./.git/objects/8f ./.git/objects/8f/7dd0e6b24f8f93777152241f7891017c613e4e ./.git/objects/8f/a44135f287836c9c362922897cdf50c8abfb0a ./.git/objects/40 ./.git/objects/40/953ed78adacbd5e220aad3cec4ac5e30b90bd8 ./.git/objects/40/17069d256c4b4b46ace0a1d3a17ab474705571 ./.git/objects/40/59ef7942ff3505c5ce73ce59f4a7bfd82ba6b9 ./.git/objects/40/3ce1a8cdab4310a2e1867567be6e847f71efd9 ./.git/objects/b2 ./.git/objects/b2/6158a9e38f0450e55de2bcff275ceb5322c6ad ./.git/objects/b2/c32bc79af68feae3d4a621976396efe0820798 ./.git/objects/9b ./.git/objects/9b/5e363c1cdd23d5c116b74644713ebc7fe73af4 ./.git/objects/9b/e2d15472a28c004e57f8e223ed6d0141689f60 ./.git/objects/29 ./.git/objects/29/bc4dcda2ef8a866b6c44a8a86f06e38e3a486a ./.git/objects/29/e47e432042221c28bcf000f50ad6a08a75dbed ./.git/objects/29/2386fb0d6dca1127e6c05c2ecdba6e4a93cea7 ./.git/objects/58 ./.git/objects/58/ab0cfc01268a2ffd914ee9e62f9af1da78d178 ./.git/objects/58/491745d53e90b2f018604a67a00e301c9dfdfd ./.git/objects/19 ./.git/objects/19/1e9420d874de0715def8962f446e3aae2e05c7 ./.git/objects/67 ./.git/objects/67/96afd7d35321930d2c306f64c3ed4d72dfe482 ./.git/objects/1c ./.git/objects/1c/9d91b14661081b506e4dee4daf78b1567e3323 ./.git/objects/1c/3c0f6bc181c8c3904ad239102c183bfc5816d4 ./.git/objects/4c ./.git/objects/4c/5a7864dd9e018485e98f98f84b706a5510ae30 ./.git/objects/92 ./.git/objects/92/36c995e938d2c12a9a49714b6258db02ae39c3 ./.git/objects/92/7360fe2e74518ab716f01252c732a7269a7631 ./.git/objects/92/d9903d9e8f6dc0216f8644be14fd733977dd79 ./.git/objects/39 ./.git/objects/39/7b5ce17fe342555c16de630d19ba1b4773fefd ./.git/objects/39/41aa48e3029a96c11c0f12f9e94043ec655815 ./.git/objects/39/f544d4c59fd91822f5189ac7c70f6066bef54b ./.git/objects/6e ./.git/objects/6e/4bee91d25e88a35f0be2fc7a14552627915afe ./.git/objects/6e/2fab67530969884622b05d64c3d049465b5efa ./.git/objects/d7 ./.git/objects/d7/775f3198f4dbbb284ac1d2bfbe0789f95bef26 ./.git/objects/d7/b4d0ca5ca71281fdc77b49820272ddea245958 ./.git/objects/4f ./.git/objects/4f/f6719cf0d54eddb41be1f095ceb9d272a92aae ./.git/objects/b0 ./.git/objects/b0/4c7a44f9ab42e495553aa332bc80e3685021b8 ./.git/objects/b0/4eb2c9a981a3a7459b0053d7b8436471066730 ./.git/objects/fd ./.git/objects/fd/eb0e5a19478cca5377cb47fe41426975109205 ./.git/objects/fd/cdf055082dc71e0f30f962578f214e6812631e ./.git/objects/fd/ff1ae9862d61a9e117e56b3548078193cbd078 ./.git/objects/08 ./.git/objects/08/2e3a2cb843392a72074b65718bc672f56835cd ./.git/objects/ec ./.git/objects/ec/5efce500afb6393d66da480b2b529a4f4f348d ./.git/objects/ec/6fc32ccaa7ee6a6f3e732578eb4c98817deb83 ./.git/objects/16 ./.git/objects/16/252d2718003ea39fa83a16a84db4fc616d73d8 ./.git/objects/16/86d481b6ef09f351775a4dc1ce272c304df1ec ./.git/objects/2a ./.git/objects/2a/6f80a64c07b516b56c681e9d6e75598b43b207 ./.git/objects/27 ./.git/objects/27/045100d894b6044d1ae548948bdfa8b2b74874 ./.git/objects/31 ./.git/objects/31/9b57b742825237cdbd9b368d9cce7127be9775 ./.git/objects/28 ./.git/objects/28/77fdeda6264e50d9a6ec4cafa505de0507cbac ./.git/objects/28/7c7c56177b382323e8fb3b41db8e02d6b8bd1c ./.git/objects/28/bfeae2edb4cd27c3323cc44ada958aea2ec165 ./.git/objects/64 ./.git/objects/64/dbea3ab74738f8ee05cf874665a7c7181c5649 ./.git/objects/9a ./.git/objects/9a/03b54f19d91702674f804179c0d86dc8f763f2 ./.git/objects/34 ./.git/objects/34/139b81408463cd1ce871a3e954bf062e1c9711 ./.git/objects/34/912ecae4fdb5c0e898af5f0c5e2350dcad4cf0 ./.git/objects/34/d776502fcdc7f0ccc2bd972e390133526b91a0 ./.git/objects/7e ./.git/objects/7e/8a190738a7c9f6c5a6a520f817c85e41d02b46 ./.git/objects/7e/b3436415d6bb988d8c0a533f4b7fc2f66491aa ./.git/objects/7f ./.git/objects/7f/423a93c268c328b5e161d986d4476e2cf4f571 ./.git/objects/7f/c7ab857ad56796463f01c4f1cfc89e378ca221 ./.git/objects/7f/10d6e0684b637206d6919b5956a1ac6ed37e49 ./.git/objects/13 ./.git/objects/13/4908aac9fe7db898b18a0a7e154072c1a3d7a2 ./.git/objects/f9 ./.git/objects/f9/85215f4f91d9cc3b848e56f78aa519ae49b5fa ./.git/objects/89 ./.git/objects/89/abfc5bdc924ff5551bfaff18de67741966b15d ./.git/objects/89/1c6f722bff534ac88c0dde8e7e63454d199296 ./.git/objects/89/735db4f10c18709ada2dc788a9743565f55388 ./.git/objects/89/a9e26eeb0a3ffd689ab5e98e43a21a1c0a87ae ./.git/objects/89/855435ff72be41295f28ee57c2bee30202de47 ./.git/objects/b1 ./.git/objects/b1/c385a303bc2dd3b850b41a1ae0410af2c5786a ./.git/objects/b1/eefe4521c5ef85f8b779add575aecf58393ce5 ./.git/objects/b1/bacc7a0b15fb01e09e1a59ee6e5bdfc2925b54 ./.git/objects/b1/ec612772c1c2249e6af3e7ba77585ee5c13c58 ./.git/objects/ff ./.git/objects/ff/3defee152ceda6082a9dc5040cd433c61efcf9 ./.git/objects/ff/f440d7c7f9aad902701b385561ddc8b77f8fe3 ./.git/objects/e5 ./.git/objects/e5/3214c9e3cad529dc0d4dfb61b48f478bfbbd4c ./.git/objects/e5/f4ff38c22af8c8dc51a7c94b4f1fb83b6558e5 ./.git/objects/e1 ./.git/objects/e1/865c1c5fd94104ed9bacb4cd53adfcd83a9697 ./.git/objects/7b ./.git/objects/7b/a0dbd949f60a1559d96d911cc33efc6939d01c ./.git/objects/7b/ea82ee2c4c1021b2e20ad5276414d1b4246c47 ./.git/objects/3c ./.git/objects/3c/63515ea22b572d39b224cc508908853084b123 ./.git/objects/8e ./.git/objects/8e/272b49dc5f3be82d469086ca9d3bed7253e70f ./.git/objects/8e/749d82d91ba0123f0bb4ebf646857049b8ef0c ./.git/objects/c9 ./.git/objects/c9/df108c929b2e5a312cd86c704c090013039e69 ./.git/objects/c9/e2566ac9d03be1f74c0ffb437998644dd60e02 ./.git/objects/ab ./.git/objects/ab/52adec5fd340b834de7014d1f3471728801848 ./.git/objects/ab/22631c8807eda2cb9fa48606aa58cbdb7dd1f4 ./.git/objects/ab/0db94c4fba3033a1993b146fcb7d4e6fad191f ./.git/objects/6b ./.git/objects/6b/c97371f4936bd31bf71f37d410f67879d208fd ./.git/objects/6b/91cabb14b820197c4a396e195d6cf8dcc18eb3 ./.git/objects/52 ./.git/objects/52/9076f7a1acb9707376f59e0e1248c348867e34 ./.git/objects/f1 ./.git/objects/f1/84063fe783cae53b303f169c9af5bca7b0f82c ./.git/objects/f1/6282f7f2786e1f9f1130343dc8c94b0b6dbf9a ./.git/objects/77 ./.git/objects/77/f0dc81400956ade5be5598af329b46c0fdeab9 ./.git/objects/77/f3677d9db06f94d516209acdfc19569736cc9a ./.git/objects/77/b205d10b78dc1cc7b318d8ad3ef866f0b88435 ./.git/objects/77/11a20542d388d93aa990522a45a432c2e5b61b ./.git/objects/00 ./.git/objects/00/deef1c92d3b244f7392a54e2e0da3fcf73cccd ./.git/objects/aa ./.git/objects/aa/55b7f297a28c5663cb8051c5f4e5431150e36a ./.git/objects/aa/056834a4ab2e1d476b371a91206c396affa82b ./.git/objects/de ./.git/objects/de/11623e687555a843d60ecc3f0c70f550e98e3d ./.git/objects/de/19613e554cca5fab317d3605f5b0ad8a8f5711 ./.git/objects/de/3effaea36556b96c74d86abf327517b289e3b7 ./.git/objects/55 ./.git/objects/55/04a585b2d05749a197cc648d4948585b002aeb ./.git/objects/55/5671ae38e662bc02b3e4f84af337732c725c41 ./.git/objects/55/ac449d0e9a26a294d47152e964564bebf0cbb7 ./.git/objects/55/1b2391f3cec5b8a7c6971bb6a4043f273eee8e ./.git/objects/69 ./.git/objects/69/6bcb9994deb32a6198dbe7683bc43e33fa8a9f ./.git/objects/d6 ./.git/objects/d6/c954feb40f1ee75fdcf00ca57f5c0d3d2e0f99 ./.git/objects/d6/c49da67ff56cbfc86661c5dfffb3b144ed5eb0 ./.git/objects/d6/811902b9ad236aad771ce776e1332736f7d88f ./.git/objects/2c ./.git/objects/2c/33e2d59e07e20924a9b25c6c737ad228ca9b0f ./.git/objects/2c/7cf5ed16ae8e4d7333984cbebaff7962b4eaef ./.git/objects/2c/6a5f8dd2ccd70f29683915413d5a7afb0c38e0 ./.git/objects/2c/ea4a57dae3d943c974d35343fd14f857e4a537 ./.git/objects/2c/90b9d946389975380bd8b96ab03a5c325ca355 ./.git/objects/fb ./.git/objects/fb/143505c55d0b75752d2077621e7f6a057dbe0a ./.git/objects/0b ./.git/objects/0b/e9761371a503b2c6d83d8f7846543666377bab ./.git/objects/95 ./.git/objects/95/26ddc2f80b69eb676be5908b863e221cc55311 ./.git/objects/95/6fa5bf5ff46970f3646bb9d3a354587ce7a758 ./.git/objects/95/d981e795f5c2beb635a3e70f3ddbfede70fbb8 ./.git/objects/b8 ./.git/objects/b8/b07af1a1bc02d22ca70807a2e4604ed94bca68 ./.git/objects/65 ./.git/objects/65/2752f82065b53bd9e241d3b1ee260dd0dc7787 ./.git/objects/65/88c2c23bcac12f9692c2cd06480cee422c1c8d ./.git/objects/65/29f3b232b42e48a7ef1f935c765e60f34ef170 ./.git/objects/65/b10e153969f46f3d80b866741c0151876da8e7 ./.git/objects/65/964392595e262f0571912b5bacd9c999b002c4 ./.git/objects/c7 ./.git/objects/c7/7f3f64c1e9bfca7efb514ba08af74c9fae2885 ./.git/objects/94 ./.git/objects/94/87dd0b25009cbd8debaf3cb2edc383790677a5 ./.git/objects/42 ./.git/objects/42/f4ec8e259667b739c89b30684fa10b1dc8ea3d ./.git/objects/53 ./.git/objects/53/27fba844b2bc564d0aa3f1e3eb930bac3fb032 ./.git/objects/53/5ed8fc72b4b1e307dd19e89267438c4423db3a ./.git/objects/35 ./.git/objects/35/deb323feeaf3ca7e9bc101029176e11734d199 ./.git/objects/35/2afae96809d801c4b45997ee4431e5bb680ede ./.git/objects/35/fd399b11365e08ffbe39585abd3be44321c406 ./.git/objects/35/d2c09301c92eab37e03723c505065e494e10d1 ./.git/objects/35/cc754c3415cc8aad653e8b09af109fe391711a ./.git/objects/a1 ./.git/objects/a1/6cb5eafaef7a2354723f9c54d400f8ee743818 ./.git/objects/37 ./.git/objects/37/581301a02ffae12602a136cad472ea76cbdb8d ./.git/objects/97 ./.git/objects/97/26766d221f3303009799db3e7ea3bec6ed2cfe ./.git/objects/97/b4363d1844eda0f9979ff4734d54a160ea6064 ./.git/objects/97/e8f520105d1f196900c45665086a68b569b7e8 ./.git/objects/ba ./.git/objects/ba/cd1431be4d953a1388bbb2685601f8b66b6710 ./.git/objects/e6 ./.git/objects/e6/f4ae3427fdc975b344464f9437fd6e783cbc2d ./.git/objects/e6/1fa3ced7bb7e13d8ee87f4eac3d1f00cb30ccb ./.git/objects/e2 ./.git/objects/e2/c6fe08e2c69707b9817a09375f099e1a93efc1 ./.git/objects/b7 ./.git/objects/b7/eab6d5e5b62a0a594a2b52998cecb5ec993800 ./.git/objects/b7/306f863c71df9b62eb25319df5aa04de67d1ed ./.git/objects/b7/755aefc6109b0581f359cfef5050110780bdc5 ./.git/objects/b7/6d3f36ede46cd4e3868631cd56d2f89ca420c0 ./.git/objects/72 ./.git/objects/72/f7b77e29f727976e5cef2bbf573ff3ed2be79f ./.git/objects/25 ./.git/objects/25/0e21592a948efb3b81f3d325d5e6a92f7b57bb ./.git/objects/25/d7ba5250934e6ccf724f22997447dd929a992c ./.git/objects/93 ./.git/objects/93/0be3835b8225191fc3e25bac75b46f59f1e4ec ./.git/objects/93/468fafb296570203c5ea7f53f3b0ca969b781b ./.git/objects/a7 ./.git/objects/a7/665a4d00775a6736b3bf9251fd402ed5214b0a ./.git/objects/a7/eb3f631f1391d84d787c36d5d81f1db6d64ff4 ./.git/objects/5f ./.git/objects/5f/2e350ec9cc6ed80e7ec93285d796b50ded711b ./.git/objects/6d ./.git/objects/6d/a9005dd1a094e5fdd61f98d55552c8ed25b758 ./.git/objects/6d/d60283ba8de90e73c86a0a1b3a0262faa83ca9 ./.git/objects/6d/0ea5ad50c394ef01a3691451aa546d2ad7aa3a ./.git/objects/4a ./.git/objects/4a/254c4789f8b2cfcfb690215dd3bf16774b060f ./.git/objects/4a/97cd73b86af93d38715655b2922602bf5effd6 ./.git/objects/4a/91acf8a657f209e77074dea27f43dece276dd9 ./.git/objects/12 ./.git/objects/12/cd765ea7be32a73ea2ec12268ccc7a978dd975 ./.git/objects/12/848fa310de1e10eb83f41ef8359b148f3ed74a ./.git/objects/12/0d81b2e9e89ed11a8c86fcaac0f19f44b5f4eb ./.git/objects/0c ./.git/objects/0c/caecffa9374685010200f29c869dce83ed02be ./.git/objects/fc ./.git/objects/fc/8440f85ef023184513b2b606ee6e0b40e5c6e9 ./.git/objects/fc/986c42168c88cefaefd8a8201d4455b4205672 ./.git/objects/fc/0781a4dc652c45cdf8122833f5f1638fe087ca ./.git/objects/0f ./.git/objects/0f/1f15d28a517a5dee0e6d81a1804c02380c26f3 ./.git/objects/f0 ./.git/objects/f0/0a2246063ebd8671cafe9983de72bbc6e45f4c ./.git/objects/96 ./.git/objects/96/e4b97449ae85fad317880fe76a35207c9d419a ./.git/objects/96/67c6e2e8bfa8504c9af78bcfc698418349a3d1 ./.git/objects/96/005d21f7fc36c9c9a8767c7b457e51730aa953 ./.git/objects/4b ./.git/objects/4b/7bd2c810157b639d753ee04bafa89fd31d7c9e ./.git/objects/4b/7646b2252c04719e5b897e28f35510415a5a3a ./.git/description ./.git/config ./.git/index ./.git/ORIG_HEAD ./.git/refs ./.git/refs/remotes ./.git/refs/remotes/drup ./.git/refs/remotes/drup/master ./.git/refs/remotes/drup/rgrinberg-pp ./.git/refs/remotes/drup/no_exception ./.git/refs/remotes/origin ./.git/refs/remotes/origin/pp ./.git/refs/remotes/origin/master ./.git/refs/remotes/origin/re_automata-module-refactor ./.git/refs/remotes/origin/format-group ./.git/refs/remotes/origin/re_str-infinite-loop-fix ./.git/refs/remotes/origin/re_str-fixes ./.git/refs/remotes/origin/prepare-1.6.1 ./.git/refs/remotes/origin/travis-403 ./.git/refs/remotes/origin/benchmarks ./.git/refs/remotes/origin/HEAD ./.git/refs/remotes/origin/re-cleanups ./.git/refs/remotes/origin/exec-no-group ./.git/refs/remotes/origin/prepare-1.6.0 ./.git/refs/remotes/origin/4.00-compat ./.git/refs/remotes/origin/labelize-match-str ./.git/refs/remotes/origin/status-lazy ./.git/refs/remotes/origin/dead-code-deriv ./.git/refs/remotes/gt ./.git/refs/remotes/gt/master ./.git/refs/heads ./.git/refs/heads/master ./.git/refs/heads/re_automata-module-refactor ./.git/refs/heads/re_cset-abstract ./.git/refs/heads/re_str-infinite-loop-fix ./.git/refs/heads/re_str-fixes ./.git/refs/heads/infinite-loop-cleanup ./.git/refs/heads/dev ./.git/refs/heads/re-cleanups ./.git/refs/heads/status-lazy ./.git/refs/heads/exec-no-group-with-bench ./.git/refs/heads/dead-code-deriv ./.git/refs/tags ./.git/refs/tags/1.3.0 ./.git/refs/tags/1.1.0 ./.git/refs/tags/1.2.2 ./.git/refs/tags/1.6.1 ./.git/refs/tags/1.2.0 ./.git/refs/tags/1.6.0 ./.git/refs/tags/1.3.2 ./.git/refs/tags/1.3.1 ./.git/refs/tags/1.2.1 ./.git/refs/tags/1.5.0 ./.git/refs/tags/1.0.0 ./.git/refs/tags/1.4.1 ./.git/HEAD ./.git/branches ./.git/info ./.git/info/exclude ./.git/FETCH_HEAD ./.git/logs ./.git/logs/refs ./.git/logs/refs/remotes ./.git/logs/refs/remotes/drup ./.git/logs/refs/remotes/drup/master ./.git/logs/refs/remotes/drup/rgrinberg-pp ./.git/logs/refs/remotes/drup/no_exception ./.git/logs/refs/remotes/origin ./.git/logs/refs/remotes/origin/pp ./.git/logs/refs/remotes/origin/master ./.git/logs/refs/remotes/origin/re_automata-module-refactor ./.git/logs/refs/remotes/origin/format-group ./.git/logs/refs/remotes/origin/re_str-infinite-loop-fix ./.git/logs/refs/remotes/origin/re_str-fixes ./.git/logs/refs/remotes/origin/prepare-1.6.1 ./.git/logs/refs/remotes/origin/travis-403 ./.git/logs/refs/remotes/origin/benchmarks ./.git/logs/refs/remotes/origin/HEAD ./.git/logs/refs/remotes/origin/re-cleanups ./.git/logs/refs/remotes/origin/exec-no-group ./.git/logs/refs/remotes/origin/prepare-1.6.0 ./.git/logs/refs/remotes/origin/4.00-compat ./.git/logs/refs/remotes/origin/labelize-match-str ./.git/logs/refs/remotes/origin/status-lazy ./.git/logs/refs/remotes/origin/dead-code-deriv ./.git/logs/refs/remotes/gt ./.git/logs/refs/remotes/gt/master ./.git/logs/refs/heads ./.git/logs/refs/heads/master ./.git/logs/refs/heads/re_automata-module-refactor ./.git/logs/refs/heads/re_cset-abstract ./.git/logs/refs/heads/re_str-infinite-loop-fix ./.git/logs/refs/heads/re_str-fixes ./.git/logs/refs/heads/infinite-loop-cleanup ./.git/logs/refs/heads/dev ./.git/logs/refs/heads/re-cleanups ./.git/logs/refs/heads/status-lazy ./.git/logs/refs/heads/exec-no-group-with-bench ./.git/logs/refs/heads/dead-code-deriv ./.git/logs/HEAD ./.git/hooks ./.git/hooks/prepare-commit-msg.sample ./.git/hooks/pre-commit.sample ./.git/hooks/update.sample ./.git/hooks/pre-rebase.sample ./.git/hooks/pre-push.sample ./.git/hooks/pre-applypatch.sample ./.git/hooks/applypatch-msg.sample ./.git/hooks/post-update.sample ./.git/hooks/commit-msg.sample ./.git/packed-refs ./_build ./_build/oUnit-test_perl-rgcaml#02.log ./_build/oUnit-test_str.cache ./_build/lib ./_build/lib/re.a ./_build/lib/re_emacs.o ./_build/lib/re_glob.mllib ./_build/lib/re_posix.cmi ./_build/lib/re_str.cmi ./_build/lib/re_perl.cmx ./_build/lib/re_glob.cmi ./_build/lib/re.mli ./_build/lib/re_pcre.annot ./_build/lib/re_emacs.annot ./_build/lib/re_cset.ml ./_build/lib/re_fmt.o ./_build/lib/re_perl.mli.depends ./_build/lib/re_posix.cma ./_build/lib/re_perl.cmi ./_build/lib/re_glob.o ./_build/lib/re_str.cmti ./_build/lib/re_automata.ml ./_build/lib/re_str.mli.depends ./_build/lib/re.ml ./_build/lib/re_emacs.mli ./_build/lib/re_pcre.cmx ./_build/lib/re_perl.cmt ./_build/lib/re_posix.cmti ./_build/lib/re_glob.mldylib ./_build/lib/re_pcre.mli ./_build/lib/re.cmti ./_build/lib/re_emacs.mli.depends ./_build/lib/re_perl.a ./_build/lib/re_pcre.cmxa ./_build/lib/re_str.cmxa ./_build/lib/re_cset.ml.depends ./_build/lib/re_glob.cmxs ./_build/lib/re_pcre.a ./_build/lib/re_perl.mldylib ./_build/lib/re.cmxa ./_build/lib/re_pcre.cmo ./_build/lib/re_pcre.cmt ./_build/lib/re_str.annot ./_build/lib/re_posix.mli ./_build/lib/re_perl.mli ./_build/lib/re_cset.cmt ./_build/lib/re.mli.depends ./_build/lib/re.mldylib ./_build/lib/re_str.cmx ./_build/lib/re_pcre.o ./_build/lib/re_automata.cmo ./_build/lib/re_posix.mldylib ./_build/lib/re_automata.mli ./_build/lib/re_cset.annot ./_build/lib/re_fmt.cmt ./_build/lib/re_posix.a ./_build/lib/re_glob.ml ./_build/lib/re.cmxs ./_build/lib/re.cmi ./_build/lib/re_str.cmt ./_build/lib/re_pcre.cmxs ./_build/lib/re_pcre.mli.depends ./_build/lib/re_emacs.ml ./_build/lib/re_fmt.cmi ./_build/lib/re_perl.ml.depends ./_build/lib/re_emacs.cmxa ./_build/lib/re_pcre.mllib ./_build/lib/re.o ./_build/lib/re_pcre.cmi ./_build/lib/re_emacs.cmo ./_build/lib/re_glob.cma ./_build/lib/re_str.a ./_build/lib/re.cmt ./_build/lib/re_str.o ./_build/lib/re_cset.cmti ./_build/lib/re_posix.annot ./_build/lib/re.ml.depends ./_build/lib/re_posix.cmo ./_build/lib/re.annot ./_build/lib/re_automata.cmx ./_build/lib/re_perl.cma ./_build/lib/re_posix.cmx ./_build/lib/re_perl.annot ./_build/lib/re_glob.cmxa ./_build/lib/re_glob.mli ./_build/lib/re_cset.cmo ./_build/lib/re_cset.cmx ./_build/lib/re_glob.a ./_build/lib/re_cset.cmi ./_build/lib/re_str.mldylib ./_build/lib/re_pcre.cmti ./_build/lib/re_automata.mli.depends ./_build/lib/re.mllib ./_build/lib/re_posix.mllib ./_build/lib/re_emacs.cmxs ./_build/lib/re_fmt.annot ./_build/lib/re_emacs.cmt ./_build/lib/re_fmt.cmo ./_build/lib/re_pcre.ml ./_build/lib/re_glob.cmti ./_build/lib/re_glob.cmx ./_build/lib/re_posix.mli.depends ./_build/lib/re_emacs.cmti ./_build/lib/re_str.ml.depends ./_build/lib/re_automata.cmi ./_build/lib/re_emacs.mldylib ./_build/lib/re_pcre.cma ./_build/lib/re_glob.cmt ./_build/lib/re_pcre.ml.depends ./_build/lib/re_posix.cmxs ./_build/lib/re_automata.annot ./_build/lib/re_emacs.a ./_build/lib/re_posix.cmxa ./_build/lib/re_pcre.mldylib ./_build/lib/re_cset.mli ./_build/lib/re_str.cmxs ./_build/lib/re_posix.o ./_build/lib/re_emacs.mllib ./_build/lib/re_perl.cmo ./_build/lib/re_cset.mli.depends ./_build/lib/re_str.mli ./_build/lib/re_glob.ml.depends ./_build/lib/re_posix.cmt ./_build/lib/re_perl.o ./_build/lib/re_str.cma ./_build/lib/re.cma ./_build/lib/re_emacs.cmx ./_build/lib/re_fmt.cmx ./_build/lib/re_str.cmo ./_build/lib/re_glob.annot ./_build/lib/re_perl.cmti ./_build/lib/re_perl.ml ./_build/lib/re_perl.cmxs ./_build/lib/re.cmo ./_build/lib/re_fmt.ml.depends ./_build/lib/re_posix.ml.depends ./_build/lib/re_automata.ml.depends ./_build/lib/re_fmt.ml ./_build/lib/re_perl.mllib ./_build/lib/re_glob.mli.depends ./_build/lib/re_emacs.cmi ./_build/lib/re.cmx ./_build/lib/re_emacs.ml.depends ./_build/lib/re_automata.o ./_build/lib/re_posix.ml ./_build/lib/re_perl.cmxa ./_build/lib/re_str.ml ./_build/lib/re_cset.o ./_build/lib/re_glob.cmo ./_build/lib/re_str.mllib ./_build/lib/re_emacs.cma ./_build/lib/re_automata.cmt ./_build/lib/re_automata.cmti ./_build/oUnit-test_perl-rgcaml#01.log ./_build/lib_test ./_build/lib_test/test_glob.ml.depends ./_build/lib_test/test_emacs.cmo ./_build/lib_test/test_glob.cmt ./_build/lib_test/test_easy.ml ./_build/lib_test/test_str.cmi ./_build/lib_test/re_match.native ./_build/lib_test/test_emacs.ml ./_build/lib_test/test_glob.cmo ./_build/lib_test/test_pcre.cmt ./_build/lib_test/re_match.ml ./_build/lib_test/re_match.cmo ./_build/lib_test/test_pcre.cmi ./_build/lib_test/fort_unit.cmxa ./_build/lib_test/fort_unit.cmo ./_build/lib_test/re_match.o ./_build/lib_test/test_pcre.cmx ./_build/lib_test/re_match.ml.depends ./_build/lib_test/fort_unit.cmt ./_build/lib_test/test_glob.ml ./_build/lib_test/test_str.o ./_build/lib_test/test_perl.native ./_build/lib_test/re_match.cmx ./_build/lib_test/fort_unit.mllib ./_build/lib_test/test_perl.ml ./_build/lib_test/test_perl.annot ./_build/lib_test/fort_unit.ml ./_build/lib_test/test_re.native ./_build/lib_test/test_perl.cmt ./_build/lib_test/test_emacs.o ./_build/lib_test/test_easy.cmi ./_build/lib_test/test_pcre.o ./_build/lib_test/test_emacs.ml.depends ./_build/lib_test/test_emacs.cmx ./_build/lib_test/test_str.cmo ./_build/lib_test/test_perl.cmx ./_build/lib_test/fort_unit.mldylib ./_build/lib_test/re_match.cmt ./_build/lib_test/test_pcre.cmo ./_build/lib_test/test_easy.cmo ./_build/lib_test/fort_unit.cma ./_build/lib_test/test_str.cmx ./_build/lib_test/test_easy.cmx ./_build/lib_test/test_pcre.native ./_build/lib_test/test_emacs.cmt ./_build/lib_test/fort_unit.o ./_build/lib_test/fort_unit.cmx ./_build/lib_test/test_re.cmo ./_build/lib_test/test_glob.cmi ./_build/lib_test/fort_unit.a ./_build/lib_test/test_easy.annot ./_build/lib_test/re_match.annot ./_build/lib_test/test_emacs.native ./_build/lib_test/test_emacs.annot ./_build/lib_test/test_re.cmx ./_build/lib_test/fort_unit.annot ./_build/lib_test/test_re.cmi ./_build/lib_test/test_emacs.cmi ./_build/lib_test/test_perl.cmo ./_build/lib_test/test_re.annot ./_build/lib_test/test_easy.native ./_build/lib_test/test_pcre.annot ./_build/lib_test/test_glob.native ./_build/lib_test/test_glob.cmx ./_build/lib_test/test_str.cmt ./_build/lib_test/test_re.cmt ./_build/lib_test/test_re.ml.depends ./_build/lib_test/test_pcre.ml ./_build/lib_test/test_glob.o ./_build/lib_test/fort_unit.ml.depends ./_build/lib_test/test_easy.o ./_build/lib_test/test_perl.cmi ./_build/lib_test/fort_unit.cmi ./_build/lib_test/test_pcre.ml.depends ./_build/lib_test/test_perl.ml.depends ./_build/lib_test/re_match.cmi ./_build/lib_test/test_str.ml.depends ./_build/lib_test/fort_unit.cmxs ./_build/lib_test/test_re.o ./_build/lib_test/test_str.annot ./_build/lib_test/test_easy.ml.depends ./_build/lib_test/test_str.ml ./_build/lib_test/test_str.native ./_build/lib_test/test_re.ml ./_build/lib_test/test_glob.annot ./_build/lib_test/test_easy.cmt ./_build/lib_test/test_perl.o ./_build/_digests ./_build/oUnit-test_emacs-rgcaml#02.log ./_build/benchmarks ./_build/benchmarks/benchmark.cmt ./_build/benchmarks/benchmark.cmx ./_build/benchmarks/benchmark.ml ./_build/benchmarks/benchmark.cmi ./_build/benchmarks/benchmark.cmo ./_build/benchmarks/benchmark.ml.depends ./_build/benchmarks/benchmark.native ./_build/benchmarks/benchmark.annot ./_build/benchmarks/benchmark.o ./_build/myocamlbuild.cmi ./_build/oUnit-test_re.cache ./_build/oUnit-test_re-rgcaml#02.log ./_build/myocamlbuild.cmx ./_build/_log ./_build/ocamlc.where ./_build/oUnit-test_emacs-rgcaml#00.log ./_build/oUnit-test_emacs-rgcaml#01.log ./_build/oUnit-test_perl-rgcaml#00.log ./_build/oUnit-test_perl.cache ./_build/oUnit-test_str-rgcaml#01.log ./_build/oUnit-test_str-rgcaml#00.log ./_build/oUnit-test_re-rgcaml#00.log ./_build/oUnit-anon.cache ./_build/myocamlbuild.o ./_build/oUnit-test_emacs.cache ./_build/oUnit-test_str-rgcaml#02.log ./_build/myocamlbuild ./_build/oUnit-test_re-rgcaml#01.log ./_build/myocamlbuild.ml ./setup.log ./.travis.yml ./_tags ./test_pcre.native ./LICENSE ./test_emacs.native ./README.md ./TODO.txt ./test_easy.native ./benchmark.native ./test_glob.native ./tags ./dev.org ./INSTALL ./configure ./Makefile ./CHANGES ./opam ./test_str.native ./myocamlbuild.ml ./compare.pl ocaml-re-1.9.0/benchmarks/http-requests.txt000066400000000000000000000516021345204770300207370ustar00rootroot00000000000000GET / HTTP/1.1 Host: www.reddit.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive GET /reddit.v_EZwRzV-Ns.css HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: text/css,*/*;q=0.1 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /reddit-init.en-us.O1zuMqOOQvY.js HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /reddit.en-us.31yAfSoTsfo.js HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /kill.png HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /icon.png HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive GET /favicon.ico HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive GET /AMZM4CWd6zstSC8y.jpg HTTP/1.1 Host: b.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /jz1d5Nm0w97-YyNm.jpg HTTP/1.1 Host: b.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /aWGO99I6yOcNUKXB.jpg HTTP/1.1 Host: a.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /rZ_rD5TjrJM0E9Aj.css HTTP/1.1 Host: e.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: text/css,*/*;q=0.1 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /tmsPwagFzyTvrGRx.jpg HTTP/1.1 Host: a.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /KYgUaLvXCK3TCEJx.jpg HTTP/1.1 Host: a.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /81pzxT5x2ozuEaxX.jpg HTTP/1.1 Host: e.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /MFqCUiUVPO5V8t6x.jpg HTTP/1.1 Host: a.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /TFpYTiAO5aEowokv.jpg HTTP/1.1 Host: e.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /eMWMpmm9APNeNqcF.jpg HTTP/1.1 Host: e.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /S-IpsJrOKuaK9GZ8.jpg HTTP/1.1 Host: c.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /3V6dj9PDsNnheDXn.jpg HTTP/1.1 Host: c.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /wQ3-VmNXhv8sg4SJ.jpg HTTP/1.1 Host: c.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /ixd1C1njpczEWC22.jpg HTTP/1.1 Host: c.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /nGsQj15VyOHMwmq8.jpg HTTP/1.1 Host: c.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /zT4yQmDxQLbIxK1b.jpg HTTP/1.1 Host: c.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /L5e1HcZLv1iu4nrG.jpg HTTP/1.1 Host: f.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /WJFFPxD8X4JO_lIG.jpg HTTP/1.1 Host: f.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /hVMVTDdjuY3bQox5.jpg HTTP/1.1 Host: f.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /rnWf8CjBcyPQs5y_.jpg HTTP/1.1 Host: f.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /gZJL1jNylKbGV4d-.jpg HTTP/1.1 Host: d.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /aNd2zNRLXiMnKUFh.jpg HTTP/1.1 Host: c.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /droparrowgray.gif HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.redditstatic.com/reddit.v_EZwRzV-Ns.css GET /sprite-reddit.an0Lnf61Ap4.png HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.redditstatic.com/reddit.v_EZwRzV-Ns.css GET /ga.js HTTP/1.1 Host: www.google-analytics.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ If-Modified-Since: Tue, 29 Oct 2013 19:33:51 GMT GET /reddit/ads.html?sr=-reddit.com&bust2 HTTP/1.1 Host: static.adzerk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /pixel/of_destiny.png?v=hOlmDALJCWWdjzfBV4ZxJPmrdCLWB%2Ftq7Z%2Ffp4Q%2FxXbVPPREuMJMVGzKraTuhhNWxCCwi6yFEZg%3D&r=783333388 HTTP/1.1 Host: pixel.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /UNcO-h_QcS9PD-Gn.jpg HTTP/1.1 Host: c.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://e.thumbs.redditmedia.com/rZ_rD5TjrJM0E9Aj.css GET /welcome-lines.png HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.redditstatic.com/reddit.v_EZwRzV-Ns.css GET /welcome-upvote.png HTTP/1.1 Host: www.redditstatic.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.redditstatic.com/reddit.v_EZwRzV-Ns.css GET /__utm.gif?utmwv=5.5.1&utms=1&utmn=720496082&utmhn=www.reddit.com&utme=8(site*srpath*usertype*uitype)9(%20reddit.com*%20reddit.com-GET_listing*guest*web)11(3!2)&utmcs=UTF-8&utmsr=2560x1600&utmvp=1288x792&utmsc=24-bit&utmul=en-us&utmje=1&utmfl=13.0%20r0&utmdt=reddit%3A%20the%20front%20page%20of%20the%20internet&utmhid=2129416330&utmr=-&utmp=%2F&utmht=1400862512705&utmac=UA-12131688-1&utmcc=__utma%3D55650728.585571751.1400862513.1400862513.1400862513.1%3B%2B__utmz%3D55650728.1400862513.1.1.utmcsr%3D(direct)%7Cutmccn%3D(direct)%7Cutmcmd%3D(none)%3B&utmu=qR~ HTTP/1.1 Host: www.google-analytics.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /ImnpOQhbXUPkwceN.png HTTP/1.1 Host: a.thumbs.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /ajax/libs/jquery/1.7.1/jquery.min.js HTTP/1.1 Host: ajax.googleapis.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2 GET /__utm.gif?utmwv=5.5.1&utms=2&utmn=1493472678&utmhn=www.reddit.com&utmt=event&utme=5(AdBlock*enabled*false)(0)8(site*srpath*usertype*uitype)9(%20reddit.com*%20reddit.com-GET_listing*guest*web)11(3!2)&utmcs=UTF-8&utmsr=2560x1600&utmvp=1288x792&utmsc=24-bit&utmul=en-us&utmje=1&utmfl=13.0%20r0&utmdt=reddit%3A%20the%20front%20page%20of%20the%20internet&utmhid=2129416330&utmr=-&utmp=%2F&utmht=1400862512708&utmac=UA-12131688-1&utmni=1&utmcc=__utma%3D55650728.585571751.1400862513.1400862513.1400862513.1%3B%2B__utmz%3D55650728.1400862513.1.1.utmcsr%3D(direct)%7Cutmccn%3D(direct)%7Cutmcmd%3D(none)%3B&utmu=6R~ HTTP/1.1 Host: www.google-analytics.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /ados.js?q=43 HTTP/1.1 Host: secure.adzerk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2 GET /fetch-trackers?callback=jQuery111005268222517967478_1400862512407&ids%5B%5D=t3_25jzeq-t8_k2ii&_=1400862512408 HTTP/1.1 Host: tracker.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /ados?t=1400862512892&request={%22Placements%22:[{%22A%22:5146,%22S%22:24950,%22D%22:%22main%22,%22AT%22:5},{%22A%22:5146,%22S%22:24950,%22D%22:%22sponsorship%22,%22AT%22:8}],%22Keywords%22:%22-reddit.com%22,%22Referrer%22:%22http%3A%2F%2Fwww.reddit.com%2F%22,%22IsAsync%22:true,%22WriteResults%22:true} HTTP/1.1 Host: engine.adzerk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2 GET /pixel/of_doom.png?id=t3_25jzeq-t8_k2ii&hash=da31d967485cdbd459ce1e9a5dde279fef7fc381&r=1738649500 HTTP/1.1 Host: pixel.redditmedia.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /Extensions/adFeedback.js HTTP/1.1 Host: static.adzrk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: */* Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2 GET /Extensions/adFeedback.css HTTP/1.1 Host: static.adzrk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: text/css,*/*;q=0.1 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2 GET /reddit/ads-load.html?bust2 HTTP/1.1 Host: static.adzerk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://www.reddit.com/ GET /Advertisers/a774d7d6148046efa89403a8db635a81.jpg HTTP/1.1 Host: static.adzerk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2 GET /i.gif?e=eyJhdiI6NjIzNTcsImF0Ijo1LCJjbSI6MTE2MzUxLCJjaCI6Nzk4NCwiY3IiOjMzNzAxNSwiZGkiOiI4NmI2Y2UzYWM5NDM0MjhkOTk2ZTg4MjYwZDE5ZTE1YyIsImRtIjoxLCJmYyI6NDE2MTI4LCJmbCI6MjEwNDY0LCJrdyI6Ii1yZWRkaXQuY29tIiwibWsiOiItcmVkZGl0LmNvbSIsIm53Ijo1MTQ2LCJwYyI6MCwicHIiOjIwMzYyLCJydCI6MSwicmYiOiJodHRwOi8vd3d3LnJlZGRpdC5jb20vIiwic3QiOjI0OTUwLCJ1ayI6InVlMS01ZWIwOGFlZWQ5YTc0MDFjOTE5NWNiOTMzZWI3Yzk2NiIsInRzIjoxNDAwODYyNTkzNjQ1fQ&s=lwlbFf2Uywt7zVBFRj_qXXu7msY HTTP/1.1 Host: engine.adzerk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2 Cookie: azk=ue1-5eb08aeed9a7401c9195cb933eb7c966 GET /BurstingPipe/adServer.bs?cn=tf&c=19&mc=imp&pli=9994987&PluID=0&ord=1400862593644&rtu=-1 HTTP/1.1 Host: bs.serving-sys.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads.html?sr=-reddit.com&bust2 GET /Advertisers/63cfd0044ffd49c0a71a6626f7a1d8f0.jpg HTTP/1.1 Host: static.adzerk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads-load.html?bust2 GET /BurstingPipe/adServer.bs?cn=tf&c=19&mc=imp&pli=9962555&PluID=0&ord=1400862593645&rtu=-1 HTTP/1.1 Host: bs.serving-sys.com User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads-load.html?bust2 Cookie: S_9994987=6754579095859875029; A4=01fmFvgRnI09SF00000; u2=d1263d39-874b-4a89-86cd-a2ab0860ed4e3Zl040 GET /i.gif?e=eyJhdiI6NjIzNTcsImF0Ijo4LCJjbSI6MTE2MzUxLCJjaCI6Nzk4NCwiY3IiOjMzNzAxOCwiZGkiOiI3OTdlZjU3OWQ5NjE0ODdiODYyMGMyMGJkOTE4YzNiMSIsImRtIjoxLCJmYyI6NDE2MTMxLCJmbCI6MjEwNDY0LCJrdyI6Ii1yZWRkaXQuY29tIiwibWsiOiItcmVkZGl0LmNvbSIsIm53Ijo1MTQ2LCJwYyI6MCwicHIiOjIwMzYyLCJydCI6MSwicmYiOiJodHRwOi8vd3d3LnJlZGRpdC5jb20vIiwic3QiOjI0OTUwLCJ1ayI6InVlMS01ZWIwOGFlZWQ5YTc0MDFjOTE5NWNiOTMzZWI3Yzk2NiIsInRzIjoxNDAwODYyNTkzNjQ2fQ&s=OjzxzXAgQksbdQOHNm-bjZcnZPA HTTP/1.1 Host: engine.adzerk.net User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:15.0) Gecko/20100101 Firefox/15.0.1 Accept: image/png,image/*;q=0.8,*/*;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Referer: http://static.adzerk.net/reddit/ads-load.html?bust2 Cookie: azk=ue1-5eb08aeed9a7401c9195cb933eb7c966 GET /subscribe?host_int=1042356184&ns_map=571794054_374233948806,464381511_13349283399&user_id=245722467&nid=1399334269710011966&ts=1400862514 HTTP/1.1 Host: notify8.dropbox.com Accept-Encoding: identity Connection: keep-alive X-Dropbox-Locale: en_US User-Agent: DropboxDesktopClient/2.7.54 (Macintosh; 10.8; ('i32',); en_US) ocaml-re-1.9.0/benchmarks/tex.gitignore000066400000000000000000000035651345204770300200640ustar00rootroot00000000000000## Core latex/pdflatex auxiliary files: *.aux *.lof *.log *.lot *.fls *.out *.toc *.fmt *.fot *.cb *.cb2 ## Intermediate documents: *.dvi *-converted-to.* # these rules might exclude image files for figures etc. # *.ps # *.eps # *.pdf ## Generated if empty string is given at "Please type another file name for output:" .pdf ## Bibliography auxiliary files (bibtex/biblatex/biber): *.bbl *.bcf *.blg *-blx.aux *-blx.bib *.brf *.run.xml ## Build tool auxiliary files: *.fdb_latexmk *.synctex *.synctex(busy) *.synctex.gz *.synctex.gz(busy) *.pdfsync ## Auxiliary and intermediate files from other packages: # algorithms *.alg *.loa # achemso acs-*.bib # amsthm *.thm # beamer *.nav *.snm *.vrb # cprotect *.cpt # fixme *.lox #(r)(e)ledmac/(r)(e)ledpar *.end *.?end *.[1-9] *.[1-9][0-9] *.[1-9][0-9][0-9] *.[1-9]R *.[1-9][0-9]R *.[1-9][0-9][0-9]R *.eledsec[1-9] *.eledsec[1-9]R *.eledsec[1-9][0-9] *.eledsec[1-9][0-9]R *.eledsec[1-9][0-9][0-9] *.eledsec[1-9][0-9][0-9]R # glossaries *.acn *.acr *.glg *.glo *.gls *.glsdefs # gnuplottex *-gnuplottex-* # gregoriotex *.gaux *.gtex # hyperref *.brf # knitr *-concordance.tex # TODO Comment the next line if you want to keep your tikz graphics files *.tikz *-tikzDictionary # listings *.lol # makeidx *.idx *.ilg *.ind *.ist # minitoc *.maf *.mlf *.mlt *.mtc *.mtc[0-9] *.mtc[1-9][0-9] # minted _minted* *.pyg # morewrites *.mw # mylatexformat *.fmt # nomencl *.nlo # sagetex *.sagetex.sage *.sagetex.py *.sagetex.scmd # scrwfile *.wrt # sympy *.sout *.sympy sympy-plots-for-*.tex/ # pdfcomment *.upa *.upb # pythontex *.pytxcode pythontex-files-*/ # thmtools *.loe # TikZ & PGF *.dpth *.md5 *.auxlock # todonotes *.tdo # easy-todo *.lod # xindy *.xdy # xypic precompiled matrices *.xyc # endfloat *.ttt *.fff # Latexian TSWLatexianTemp* ## Editors: # WinEdt *.bak *.sav # Texpad .texpadtmp # Kile *.backup # KBibTeX *~[0-9]*ocaml-re-1.9.0/deprecated/000077500000000000000000000000001345204770300153255ustar00rootroot00000000000000ocaml-re-1.9.0/deprecated/dune000066400000000000000000000015131345204770300162030ustar00rootroot00000000000000(library (name re_str) (public_name re.str) (wrapped false) (modules re_str) (synopsis "Deprecated. Use Re.Str") (libraries re)) (library (name re_pcre) (public_name re.pcre) (wrapped false) (modules re_pcre) (synopsis "Deprecated. Use Re.Pcre") (libraries re)) (library (name re_perl) (public_name re.perl) (wrapped false) (modules re_perl) (synopsis "Deprecated. Use Re.Perl") (libraries re)) (library (name re_posix) (public_name re.posix) (wrapped false) (modules re_posix) (synopsis "Deprecated. Use Re.Posix") (libraries re)) (library (name re_emacs) (public_name re.emacs) (wrapped false) (modules re_emacs) (synopsis "Deprecated. Use Re.Emacs") (libraries re)) (library (name re_glob) (public_name re.glob) (wrapped false) (modules re_glob) (synopsis "Deprecated. Use Re.Glob") (libraries re)) ocaml-re-1.9.0/deprecated/re_emacs.ml000066400000000000000000000000611345204770300174320ustar00rootroot00000000000000[@@@deprecated "Use Re.Emacs"] include Re.Emacs ocaml-re-1.9.0/deprecated/re_glob.ml000066400000000000000000000000571345204770300172720ustar00rootroot00000000000000[@@@deprecated "Use Re.Glob"] include Re.Glob ocaml-re-1.9.0/deprecated/re_pcre.ml000066400000000000000000000000571345204770300173000ustar00rootroot00000000000000[@@@deprecated "Use Re.Pcre"] include Re.Pcre ocaml-re-1.9.0/deprecated/re_perl.ml000066400000000000000000000000571345204770300173110ustar00rootroot00000000000000[@@@deprecated "Use Re.Perl"] include Re.Perl ocaml-re-1.9.0/deprecated/re_posix.ml000066400000000000000000000000611345204770300175040ustar00rootroot00000000000000[@@@deprecated "Use Re.Posix"] include Re.Posix ocaml-re-1.9.0/deprecated/re_str.ml000066400000000000000000000000551345204770300171550ustar00rootroot00000000000000[@@@deprecated "Use Re.Str"] include Re.Str ocaml-re-1.9.0/dune000066400000000000000000000000451345204770300141020ustar00rootroot00000000000000(env (_ (flags (:standard -w -50))))ocaml-re-1.9.0/dune-project000066400000000000000000000000331345204770300155430ustar00rootroot00000000000000(lang dune 1.0) (name re) ocaml-re-1.9.0/dune-workspace.dev000066400000000000000000000004211345204770300166510ustar00rootroot00000000000000(lang dune 1.0) ;; This file is used by `make all-supported-ocaml-versions` (context (opam (switch 4.02.3))) (context (opam (switch 4.03.0))) (context (opam (switch 4.04.2))) (context (opam (switch 4.05.0))) (context (opam (switch 4.06.1))) (context (opam (switch 4.07.0)))ocaml-re-1.9.0/lib/000077500000000000000000000000001345204770300137735ustar00rootroot00000000000000ocaml-re-1.9.0/lib/automata.ml000066400000000000000000000451771345204770300161560ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, with linking exception; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) type sem = [ `Longest | `Shortest | `First ] type rep_kind = [ `Greedy | `Non_greedy ] type mark = int type idx = int type expr = { id : int; def : def } and def = Cst of Cset.t | Alt of expr list | Seq of sem * expr * expr | Eps | Rep of rep_kind * sem * expr | Mark of int | Erase of int * int | Before of Category.t | After of Category.t | Pmark of Pmark.t let hash_combine h accu = accu * 65599 + h module Marks = struct type t = { marks : (int * int) list ; pmarks : Pmark.Set.t } let empty = { marks = [] ; pmarks = Pmark.Set.empty } let rec merge_marks_offset old = function | [] -> old | (i, v) :: rem -> let nw' = merge_marks_offset (List.remove_assq i old) rem in if v = -2 then nw' else (i, v) :: nw' let merge old nw = { marks = merge_marks_offset old.marks nw.marks ; pmarks = Pmark.Set.union old.pmarks nw.pmarks } let rec hash_marks_offset l accu = match l with [] -> accu | (a, i) :: r -> hash_marks_offset r (hash_combine a (hash_combine i accu)) let hash m accu = hash_marks_offset m.marks (hash_combine (Hashtbl.hash m.pmarks) accu) let rec marks_set_idx idx = function | (a, -1) :: rem -> (a, idx) :: marks_set_idx idx rem | marks -> marks let marks_set_idx marks idx = { marks with marks = marks_set_idx idx marks.marks } let pp_marks ch t = match t.marks with | [] -> () | (a, i) :: r -> Format.fprintf ch "%d-%d" a i; List.iter (fun (a, i) -> Format.fprintf ch " %d-%d" a i) r end (****) let pp_sem ch k = Format.pp_print_string ch (match k with `Shortest -> "short" | `Longest -> "long" | `First -> "first") let pp_rep_kind fmt = function | `Greedy -> Format.pp_print_string fmt "Greedy" | `Non_greedy -> Format.pp_print_string fmt "Non_greedy" let rec pp ch e = let open Fmt in match e.def with Cst l -> sexp ch "cst" Cset.pp l; | Alt l -> sexp ch "alt" (list pp) l | Seq (k, e, e') -> sexp ch "seq" (triple pp_sem pp pp) (k, e, e') | Eps -> str ch "eps" | Rep (_rk, k, e) -> sexp ch "rep" (pair pp_sem pp) (k, e) | Mark i -> sexp ch "mark" int i | Pmark i -> sexp ch "pmark" int (i :> int) | Erase (b, e) -> sexp ch "erase" (pair int int) (b, e) | Before c -> sexp ch "before" Category.pp c | After c -> sexp ch "after" Category.pp c (****) let rec first f = function | [] -> None | x :: r -> match f x with None -> first f r | Some _ as res -> res (****) type ids = int ref let create_ids () = ref 0 let eps_expr = { id = 0; def = Eps } let mk_expr ids def = incr ids; { id = !ids; def = def } let empty ids = mk_expr ids (Alt []) let cst ids s = if Cset.is_empty s then empty ids else mk_expr ids (Cst s) let alt ids = function | [] -> empty ids | [c] -> c | l -> mk_expr ids (Alt l) let seq ids kind x y = match x.def, y.def with Alt [], _ -> x | _, Alt [] -> y | Eps, _ -> y | _, Eps when kind = `First -> x | _ -> mk_expr ids (Seq (kind, x, y)) let is_eps expr = match expr.def with | Eps -> true | _ -> false let eps ids = mk_expr ids Eps let rep ids kind sem x = mk_expr ids (Rep (kind, sem, x)) let mark ids m = mk_expr ids (Mark m) let pmark ids i = mk_expr ids (Pmark i) let erase ids m m' = mk_expr ids (Erase (m, m')) let before ids c = mk_expr ids (Before c) let after ids c = mk_expr ids (After c) (****) let rec rename ids x = match x.def with Cst _ | Eps | Mark _ | Pmark _ | Erase _ | Before _ | After _ -> mk_expr ids x.def | Alt l -> mk_expr ids (Alt (List.map (rename ids) l)) | Seq (k, y, z) -> mk_expr ids (Seq (k, rename ids y, rename ids z)) | Rep (g, k, y) -> mk_expr ids (Rep (g, k, rename ids y)) (****) type hash = int type mark_infos = int array type status = Failed | Match of mark_infos * Pmark.Set.t | Running module E = struct type t = | TSeq of t list * expr * sem | TExp of Marks.t * expr | TMatch of Marks.t let rec equal l1 l2 = match l1, l2 with | [], [] -> true | TSeq (l1', e1, _) :: r1, TSeq (l2', e2, _) :: r2 -> e1.id = e2.id && equal l1' l2' && equal r1 r2 | TExp (marks1, e1) :: r1, TExp (marks2, e2) :: r2 -> e1.id = e2.id && marks1 = marks2 && equal r1 r2 | TMatch marks1 :: r1, TMatch marks2 :: r2 -> marks1 = marks2 && equal r1 r2 | _ -> false let rec hash l accu = match l with | [] -> accu | TSeq (l', e, _) :: r -> hash r (hash_combine 0x172a1bce (hash_combine e.id (hash l' accu))) | TExp (marks, e) :: r -> hash r (hash_combine 0x2b4c0d77 (hash_combine e.id (Marks.hash marks accu))) | TMatch marks :: r -> hash r (hash_combine 0x1c205ad5 (Marks.hash marks accu)) let texp marks x = TExp (marks, x) let tseq kind x y rem = match x with [] -> rem | [TExp (marks, {def = Eps ; _})] -> TExp (marks, y) :: rem | _ -> TSeq (x, y, kind) :: rem let rec print_state_rec ch e y = match e with | TMatch marks -> Format.fprintf ch "@[<2>(Match@ %a)@]" Marks.pp_marks marks | TSeq (l', x, _kind) -> Format.fprintf ch "@[<2>(Seq@ "; print_state_lst ch l' x; Format.fprintf ch " %a)@]" pp x | TExp (marks, {def = Eps; _}) -> Format.fprintf ch "(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 and print_state_lst ch l y = match l with [] -> Format.fprintf ch "()" | e :: rem -> print_state_rec ch e y; List.iter (fun e -> Format.fprintf ch " | "; print_state_rec ch e y) rem let pp ch t = print_state_lst ch [t] { id = 0; def = Eps } end module State = struct type t = { idx: idx ; category: Category.t ; desc: E.t list ; mutable status: status option ; hash: hash } let dummy = { idx = -1 ; category = Category.dummy ; desc = [] ; status = None ; hash = -1 } let hash idx cat desc = E.hash desc (hash_combine idx (hash_combine (Category.to_int cat) 0)) land 0x3FFFFFFF let mk idx cat desc = { idx ; category = cat ; desc ; status = None ; hash = hash idx cat desc} let create cat e = mk 0 cat [E.TExp (Marks.empty, e)] let equal x y = (x.hash : int) = y.hash && (x.idx : int) = y.idx && Category.equal x.category y.category && E.equal x.desc y.desc let compare x y = let c = compare (x.hash : int) y.hash in if c <> 0 then c else let c = Category.compare x.category y.category in if c <> 0 then c else compare x.desc y.desc type t' = t module Table = Hashtbl.Make( struct type t = t' let equal = equal let hash t = t.hash end) end (**** Find a free index ****) type working_area = bool array ref let create_working_area () = ref [| false |] let index_count w = Array.length !w let reset_table a = Array.fill a 0 (Array.length a) false let rec mark_used_indices tbl = List.iter (function | E.TSeq (l, _, _) -> mark_used_indices tbl l | E.TExp (marks, _) | E.TMatch marks -> List.iter (fun (_, i) -> if i >= 0 then tbl.(i) <- true) marks.Marks.marks) let rec find_free tbl idx len = if idx = len || not tbl.(idx) then idx else find_free tbl (idx + 1) len let free_index tbl_ref l = let tbl = !tbl_ref in reset_table tbl; mark_used_indices tbl l; let len = Array.length tbl in let idx = find_free tbl 0 len in if idx = len then tbl_ref := Array.make (2 * len) false; idx (**** Computation of the next state ****) let remove_matches = List.filter (function E.TMatch _ -> false | _ -> true) let rec split_at_match_rec l' = function | [] -> assert false | E.TMatch _ :: r -> (List.rev l', remove_matches r) | x :: r -> split_at_match_rec (x :: l') r let split_at_match l = split_at_match_rec [] l let rec remove_duplicates prev l y = match l with [] -> ([], prev) | E.TMatch _ as x :: _ -> (* Truncate after first match *) ([x], prev) | E.TSeq (l', x, kind) :: r -> let (l'', prev') = remove_duplicates prev l' x in let (r', prev'') = remove_duplicates prev' r y in (E.tseq kind l'' x r', prev'') | E.TExp (_marks, {def = Eps; _}) as e :: r -> if List.memq y.id prev then remove_duplicates prev r y else let (r', prev') = remove_duplicates (y.id :: prev) r y in (e :: r', prev') | E.TExp (_marks, x) as e :: r -> if List.memq x.id prev then remove_duplicates prev r y else let (r', prev') = remove_duplicates (x.id :: prev) r y in (e :: r', prev') let rec set_idx idx = function | [] -> [] | E.TMatch marks :: r -> E.TMatch (Marks.marks_set_idx marks idx) :: set_idx idx r | E.TSeq (l', x, kind) :: r -> E.TSeq (set_idx idx l', x, kind) :: set_idx idx r | E.TExp (marks, x) :: r -> E.TExp ((Marks.marks_set_idx marks idx), x) :: set_idx idx r let filter_marks b e marks = {marks with Marks.marks = List.filter (fun (i, _) -> i < b || i > e) marks.Marks.marks } let rec delta_1 marks c ~next_cat ~prev_cat x rem = (*Format.eprintf "%d@." x.id;*) match x.def with Cst s -> if Cset.mem c s then E.texp marks eps_expr :: rem else rem | Alt l -> delta_2 marks c ~next_cat ~prev_cat l rem | Seq (kind, y, z) -> let y' = delta_1 marks c ~next_cat ~prev_cat y [] in delta_seq c ~next_cat ~prev_cat kind y' z rem | Rep (rep_kind, kind, y) -> let y' = delta_1 marks c ~next_cat ~prev_cat y [] in let (y'', marks') = match first (function E.TMatch marks -> Some marks | _ -> None) y' with None -> (y', marks) | Some marks' -> (remove_matches y', marks') in begin match rep_kind with `Greedy -> E.tseq kind y'' x (E.TMatch marks' :: rem) | `Non_greedy -> E.TMatch marks :: E.tseq kind y'' x rem end | Eps -> E.TMatch marks :: rem | Mark i -> let marks = { marks with Marks.marks = (i, -1) :: List.remove_assq i marks.Marks.marks } in E.TMatch marks :: rem | Pmark i -> let marks = { marks with Marks.pmarks = Pmark.Set.add i marks.Marks.pmarks } in E.TMatch marks :: rem | Erase (b, e) -> E.TMatch (filter_marks b e marks) :: rem | Before cat'' -> if Category.intersect next_cat cat'' then E.TMatch marks :: rem else rem | After cat'' -> if Category.intersect prev_cat cat'' then E.TMatch marks :: rem else rem and delta_2 marks c ~next_cat ~prev_cat l rem = match l with [] -> rem | y :: r -> delta_1 marks c ~next_cat ~prev_cat y (delta_2 marks c ~next_cat ~prev_cat r rem) and delta_seq c ~next_cat ~prev_cat kind y z rem = match first (function E.TMatch marks -> Some marks | _ -> None) y with None -> E.tseq kind y z rem | Some marks -> match kind with `Longest -> E.tseq kind (remove_matches y) z (delta_1 marks c ~next_cat ~prev_cat z rem) | `Shortest -> delta_1 marks c ~next_cat ~prev_cat z (E.tseq kind (remove_matches y) z rem) | `First -> let (y', y'') = split_at_match y in E.tseq kind y' z (delta_1 marks c ~next_cat ~prev_cat z (E.tseq kind y'' z rem)) let rec delta_3 c ~next_cat ~prev_cat x rem = match x with E.TSeq (y, z, kind) -> let y' = delta_4 c ~next_cat ~prev_cat y [] in delta_seq c ~next_cat ~prev_cat kind y' z rem | E.TExp (marks, e) -> delta_1 marks c ~next_cat ~prev_cat e rem | E.TMatch _ -> x :: rem and delta_4 c ~next_cat ~prev_cat l rem = match l with [] -> rem | y :: r -> delta_3 c ~next_cat ~prev_cat y (delta_4 c ~next_cat ~prev_cat r rem) let delta tbl_ref next_cat char st = let prev_cat = st.State.category in let (expr', _) = remove_duplicates [] (delta_4 char ~next_cat ~prev_cat st.State.desc []) eps_expr in let idx = free_index tbl_ref expr' in let expr'' = set_idx idx expr' in State.mk idx next_cat expr'' (****) let rec red_tr = function | [] | [_] as l -> l | ((s1, st1) as tr1) :: ((s2, st2) as tr2) :: rem -> if State.equal st1 st2 then red_tr ((Cset.union s1 s2, st1) :: rem) else tr1 :: red_tr (tr2 :: rem) let simpl_tr l = List.sort (fun (s1, _) (s2, _) -> compare s1 s2) (red_tr (List.sort (fun (_, st1) (_, st2) -> State.compare st1 st2) l)) (****) let prepend_deriv = List.fold_right (fun (s, x) l -> Cset.prepend s x l) let rec restrict s = function | [] -> [] | (s', x') :: rem -> let s'' = Cset.inter s s' in if Cset.is_empty s'' then restrict s rem else (s'', x') :: restrict s rem let rec remove_marks b e rem = if b > e then rem else remove_marks b (e - 1) ((e, -2) :: rem) let rec prepend_marks_expr m = function | E.TSeq (l, e', s) -> E.TSeq (prepend_marks_expr_lst m l, e', s) | E.TExp (m', e') -> E.TExp (Marks.merge m m', e') | E.TMatch m' -> E.TMatch (Marks.merge m m') and prepend_marks_expr_lst m l = List.map (prepend_marks_expr m) l let prepend_marks m = List.map (fun (s, x) -> (s, prepend_marks_expr_lst m x)) let rec deriv_1 all_chars categories marks cat x rem = match x.def with | Cst s -> Cset.prepend s [E.texp marks eps_expr] rem | Alt l -> deriv_2 all_chars categories marks cat l rem | Seq (kind, y, z) -> let y' = deriv_1 all_chars categories marks cat y [(all_chars, [])] in deriv_seq all_chars categories cat kind y' z rem | Rep (rep_kind, kind, y) -> let y' = deriv_1 all_chars categories marks cat y [(all_chars, [])] in List.fold_right (fun (s, z) rem -> let (z', marks') = match first (function E.TMatch marks -> Some marks | _ -> None) z with None -> (z, marks) | Some marks' -> (remove_matches z, marks') in Cset.prepend s (match rep_kind with `Greedy -> E.tseq kind z' x [E.TMatch marks'] | `Non_greedy -> E.TMatch marks :: E.tseq kind z' x []) rem) y' rem | Eps -> Cset.prepend all_chars [E.TMatch marks] rem | Mark i -> Cset.prepend all_chars [E.TMatch {marks with Marks.marks = ((i, -1) :: List.remove_assq i marks.Marks.marks)}] rem | Pmark _ -> Cset.prepend all_chars [E.TMatch marks] rem | Erase (b, e) -> Cset.prepend all_chars [E.TMatch {marks with Marks.marks = (remove_marks b e (filter_marks b e marks).Marks.marks)}] rem | Before cat' -> Cset.prepend (List.assq cat' categories) [E.TMatch marks] rem | After cat' -> if Category.intersect cat cat' then Cset.prepend all_chars [E.TMatch marks] rem else rem and deriv_2 all_chars categories marks cat l rem = match l with [] -> rem | y :: r -> deriv_1 all_chars categories marks cat y (deriv_2 all_chars categories marks cat r rem) and deriv_seq all_chars categories cat kind y z rem = if List.exists (fun (_s, xl) -> List.exists (function E.TMatch _ -> true | _ -> false) xl) y then let z' = deriv_1 all_chars categories Marks.empty cat z [(all_chars, [])] in List.fold_right (fun (s, y) rem -> match first (function E.TMatch marks -> Some marks | _ -> None) y with None -> Cset.prepend s (E.tseq kind y z []) rem | Some marks -> let z'' = prepend_marks marks z' in match kind with `Longest -> Cset.prepend s (E.tseq kind (remove_matches y) z []) ( prepend_deriv (restrict s z'') rem) | `Shortest -> prepend_deriv (restrict s z'') ( Cset.prepend s (E.tseq kind (remove_matches y) z []) rem) | `First -> let (y', y'') = split_at_match y in Cset.prepend s (E.tseq kind y' z []) ( prepend_deriv (restrict s z'') ( Cset.prepend s (E.tseq kind y'' z []) rem))) y rem else List.fold_right (fun (s, xl) rem -> Cset.prepend s (E.tseq kind xl z []) rem) y rem let rec deriv_3 all_chars categories cat x rem = match x with E.TSeq (y, z, kind) -> let y' = deriv_4 all_chars categories cat y [(all_chars, [])] in deriv_seq all_chars categories cat kind y' z rem | E.TExp (marks, e) -> deriv_1 all_chars categories marks cat e rem | E.TMatch _ -> Cset.prepend all_chars [x] rem and deriv_4 all_chars categories cat l rem = match l with [] -> rem | y :: r -> deriv_3 all_chars categories cat y (deriv_4 all_chars categories cat r rem) let deriv tbl_ref all_chars categories st = let der = deriv_4 all_chars categories st.State.category st.State.desc [(all_chars, [])] in simpl_tr ( List.fold_right (fun (s, expr) rem -> let (expr', _) = remove_duplicates [] expr eps_expr in (* Format.eprintf "@[<3>@[%a@]: %a / %a@]@." Cset.print s print_state expr print_state expr'; *) let idx = free_index tbl_ref expr' in let expr'' = set_idx idx expr' in List.fold_right (fun (cat', s') rem -> let s'' = Cset.inter s s' in if Cset.is_empty s'' then rem else (s'', State.mk idx cat' expr'') :: rem) categories rem) der []) (****) let flatten_match m = let ma = List.fold_left (fun ma (i, _) -> max ma i) (-1) m in let res = Array.make (ma + 1) (-1) in List.iter (fun (i, v) -> res.(i) <- v) m; res let status s = match s.State.status with Some st -> st | None -> let st = match s.State.desc with [] -> Failed | E.TMatch m :: _ -> Match (flatten_match m.Marks.marks, m.Marks.pmarks) | _ -> Running in s.State.status <- Some st; st ocaml-re-1.9.0/lib/automata.mli000066400000000000000000000051021345204770300163070ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, with linking exception; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) (* Regular expressions *) type mark = int type sem = [ `Longest | `Shortest | `First ] type rep_kind = [ `Greedy | `Non_greedy ] val pp_sem : Format.formatter -> sem -> unit val pp_rep_kind : Format.formatter -> rep_kind -> unit type expr val is_eps : expr -> bool val pp : Format.formatter -> expr -> unit type ids val create_ids : unit -> ids val cst : ids -> Cset.t -> expr val empty : ids -> expr val alt : ids -> expr list -> expr val seq : ids -> sem -> expr -> expr -> expr val eps : ids -> expr val rep : ids -> rep_kind -> sem -> expr -> expr val mark : ids -> mark -> expr val pmark : ids -> Pmark.t -> expr val erase : ids -> mark -> mark -> expr val before : ids -> Category.t -> expr val after : ids -> Category.t -> expr val rename : ids -> expr -> expr (****) (* States of the automata *) type idx = int module Marks : sig type t = { marks: (mark * idx) list ; pmarks: Pmark.Set.t } end module E : sig type t val pp : Format.formatter -> t -> unit end type hash type mark_infos = int array type status = Failed | Match of mark_infos * Pmark.Set.t | Running module State : sig type t = { idx: idx ; category: Category.t ; desc: E.t list ; mutable status: status option ; hash: hash } val dummy : t val create : Category.t -> expr -> t module Table : Hashtbl.S with type key = t end (****) (* Computation of the states following a given state *) type working_area val create_working_area : unit -> working_area val index_count : working_area -> int val delta : working_area -> Category.t -> Cset.c -> State.t -> State.t val deriv : working_area -> Cset.t -> (Category.t * Cset.t) list -> State.t -> (Cset.t * State.t) list (****) val status : State.t -> status ocaml-re-1.9.0/lib/category.ml000066400000000000000000000011241345204770300161400ustar00rootroot00000000000000 type t = int let equal (x : int) (y : int) = x = y let compare (x : int) (y : int) = compare x y let to_int x = x let pp = Format.pp_print_int let intersect x y = x land y <> 0 let (++) x y = x lor y let dummy = -1 let inexistant = 1 let letter = 2 let not_letter = 4 let newline = 8 let lastnewline = 16 let search_boundary = 32 let from_char = function (* Should match [cword] definition *) | 'a'..'z' | 'A'..'Z' | '0'..'9' | '_' | '\170' | '\181' | '\186' | '\192'..'\214' | '\216'..'\246' | '\248'..'\255' -> letter | '\n' -> not_letter ++ newline | _ -> not_letter ocaml-re-1.9.0/lib/category.mli000066400000000000000000000010001345204770300163020ustar00rootroot00000000000000(** Categories represent the various kinds of characters that can be tested by look-ahead and look-behind operations. This is more restricted than Cset, but faster. *) type t val (++) : t -> t -> t val from_char : char -> t val dummy : t val inexistant : t val letter : t val not_letter : t val newline : t val lastnewline : t val search_boundary : t val to_int : t -> int val equal : t -> t -> bool val compare : t -> t -> int val intersect : t -> t -> bool val pp : Format.formatter -> t -> unit ocaml-re-1.9.0/lib/color_map.ml000066400000000000000000000016221345204770300163010ustar00rootroot00000000000000(* In reality, this can really be represented as a bool array. The representation is best thought of as a list of all chars along with a flag: (a, 0), (b, 1), (c, 0), (d, 0), ... characters belonging to the same color are represented by sequnces of characters with the flag set to 0. *) type t = Bytes.t let make () = Bytes.make 257 '\000' let flatten cm = let c = Bytes.create 256 in let color_repr = Bytes.create 256 in let v = ref 0 in Bytes.set c 0 '\000'; Bytes.set color_repr 0 '\000'; for i = 1 to 255 do if Bytes.get cm i <> '\000' then incr v; Bytes.set c i (Char.chr !v); Bytes.set color_repr !v (Char.chr i) done; (c, Bytes.sub color_repr 0 (!v + 1), !v + 1) (* mark all the endpoints of the intervals of the char set with the 1 byte *) let split s cm = Cset.iter s ~f:(fun i j -> Bytes.set cm i '\001'; Bytes.set cm (j + 1) '\001'; ) ocaml-re-1.9.0/lib/color_map.mli000066400000000000000000000007121345204770300164510ustar00rootroot00000000000000(* Color maps exists to provide an optimization for the regex engine. The fact that some characters are entirely equivalent for some regexes means that we can use them interchangeably. A color map assigns a color to every character in our character set. Any two characters with the same color will be treated equivalently by the automaton. *) type t val make : unit -> t val flatten : t -> bytes * bytes * int val split : Cset.t -> t -> unit ocaml-re-1.9.0/lib/core.ml000066400000000000000000001072031345204770300152600ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, with linking exception; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) let rec iter n f v = if n = 0 then v else iter (n - 1) f (f v) (****) let unknown = -2 let break = -3 type match_info = | Match of Group.t | Failed | Running type state = { idx : int; (* Index of the current position in the position table. Not yet computed transitions point to a dummy state where [idx] is set to [unknown]; If [idx] is set to [break] for states that either always succeed or always fail. *) real_idx : int; (* The real index, in case [idx] is set to [break] *) next : state array; (* Transition table, indexed by color *) mutable final : (Category.t * (Automata.idx * Automata.status)) list; (* Mapping from the category of the next character to - the index where the next position should be saved - possibly, the list of marks (and the corresponding indices) corresponding to the best match *) desc : Automata.State.t (* Description of this state of the automata *) } (* Automata (compiled regular expression) *) type re = { initial : Automata.expr; (* The whole regular expression *) mutable initial_states : (Category.t * state) list; (* Initial states, indexed by initial category *) colors : Bytes.t; (* Color table *) color_repr : Bytes.t; (* Table from colors to one character of this color *) ncolor : int; (* Number of colors. *) lnl : int; (* Color of the last newline. -1 if unnecessary *) tbl : Automata.working_area; (* Temporary table used to compute the first available index when computing a new state *) states : state Automata.State.Table.t; (* States of the deterministic automata *) group_count : int (* Number of groups in the regular expression *) } let pp_re ch re = Automata.pp ch re.initial let print_re = pp_re (* Information used during matching *) type info = { re : re; (* The automata *) colors : Bytes.t; (* Color table ([x.colors = x.re.colors]) Shortcut used for performance reasons *) mutable positions : int array; (* Array of mark positions The mark are off by one for performance reasons *) pos : int; (* Position where the match is started *) last : int (* Position where the match should stop *) } (****) let category re ~color = if color = -1 then Category.inexistant (* Special category for the last newline *) else if color = re.lnl then Category.(lastnewline ++ newline ++ not_letter) else Category.from_char (Bytes.get re.color_repr color) (****) let dummy_next = [||] let unknown_state = { idx = unknown; real_idx = 0; next = dummy_next; final = []; desc = Automata.State.dummy } let mk_state ncol desc = let break_state = match Automata.status desc with | Automata.Running -> false | Automata.Failed | Automata.Match _ -> true in { idx = if break_state then break else desc.Automata.State.idx; real_idx = desc.Automata.State.idx; next = if break_state then dummy_next else Array.make ncol unknown_state; final = []; desc } let find_state re desc = try Automata.State.Table.find re.states desc with Not_found -> let st = mk_state re.ncolor desc in Automata.State.Table.add re.states desc st; st (**** Match with marks ****) let delta info cat ~color st = let desc = Automata.delta info.re.tbl cat color st.desc in let len = Array.length info.positions in if desc.Automata.State.idx = len && len > 0 then begin let pos = info.positions in info.positions <- Array.make (2 * len) 0; Array.blit pos 0 info.positions 0 len end; desc let validate info (s:string) ~pos st = let color = Char.code (Bytes.get info.colors (Char.code s.[pos])) in let cat = category info.re ~color in let desc' = delta info cat ~color st in let st' = find_state info.re desc' in st.next.(color) <- st' (* let rec loop info s pos st = if pos < info.last then let st' = st.next.(Char.code info.cols.[Char.code s.[pos]]) in let idx = st'.idx in if idx >= 0 then begin info.positions.(idx) <- pos; loop info s (pos + 1) st' end else if idx = break then begin info.positions.(st'.real_idx) <- pos; st' end else begin (* Unknown *) validate info s pos st; loop info s pos st end else st *) let rec loop info (s:string) ~pos st = if pos < info.last then let st' = st.next.(Char.code (Bytes.get info.colors (Char.code s.[pos]))) in loop2 info s ~pos st st' else st and loop2 info s ~pos st st' = if st'.idx >= 0 then begin let pos = pos + 1 in if pos < info.last then begin (* It is important to place these reads before the write *) (* But then, we don't have enough registers left to store the right position. So, we store the position plus one. *) let st'' = st'.next.(Char.code (Bytes.get info.colors (Char.code s.[pos]))) in info.positions.(st'.idx) <- pos; loop2 info s ~pos st' st'' end else begin info.positions.(st'.idx) <- pos; st' end end else if st'.idx = break then begin info.positions.(st'.real_idx) <- pos + 1; st' end else begin (* Unknown *) validate info s ~pos st; loop info s ~pos st end let rec loop_no_mark info s ~pos ~last st = if pos < last then let st' = st.next.(Char.code (Bytes.get info.colors (Char.code s.[pos]))) in if st'.idx >= 0 then loop_no_mark info s ~pos:(pos + 1) ~last st' else if st'.idx = break then st' else begin (* Unknown *) validate info s ~pos st; loop_no_mark info s ~pos ~last st end else st let final info st cat = try List.assq cat st.final with Not_found -> let st' = delta info cat ~color:(-1) st in let res = (st'.Automata.State.idx, Automata.status st') in st.final <- (cat, res) :: st.final; res let find_initial_state re cat = try List.assq cat re.initial_states with Not_found -> let st = find_state re (Automata.State.create cat re.initial) in re.initial_states <- (cat, st) :: re.initial_states; st let get_color re (s:string) pos = if pos < 0 then -1 else let slen = String.length s in if pos >= slen then -1 else if pos = slen - 1 && re.lnl <> -1 && s.[pos] = '\n' then (* Special case for the last newline *) re.lnl else Char.code (Bytes.get re.colors (Char.code s.[pos])) let rec handle_last_newline info ~pos st ~groups = let st' = st.next.(info.re.lnl) in if st'.idx >= 0 then begin if groups then info.positions.(st'.idx) <- pos + 1; st' end else if st'.idx = break then begin if groups then info.positions.(st'.real_idx) <- pos + 1; st' end else begin (* Unknown *) let color = info.re.lnl in let real_c = Char.code (Bytes.get info.colors (Char.code '\n')) in let cat = category info.re ~color in let desc' = delta info cat ~color:real_c st in let st' = find_state info.re desc' in st.next.(color) <- st'; handle_last_newline info ~pos st ~groups end let rec scan_str info (s:string) initial_state ~groups = let pos = info.pos in let last = info.last in if (last = String.length s && info.re.lnl <> -1 && last > pos && String.get s (last - 1) = '\n') then begin let info = { info with last = last - 1 } in let st = scan_str info s initial_state ~groups in if st.idx = break then st else handle_last_newline info ~pos:(last - 1) st ~groups end else if groups then loop info s ~pos initial_state else loop_no_mark info s ~pos ~last initial_state let match_str ~groups ~partial re s ~pos ~len = let slen = String.length s in let last = if len = -1 then slen else pos + len in let info = { re ; colors = re.colors; pos ; last ; positions = if groups then begin let n = Automata.index_count re.tbl + 1 in if n <= 10 then [|0;0;0;0;0;0;0;0;0;0|] else Array.make n 0 end else [||] } in let initial_cat = if pos = 0 then Category.(search_boundary ++ inexistant) else Category.(search_boundary ++ category re ~color:(get_color re s (pos - 1))) in let initial_state = find_initial_state re initial_cat in let st = scan_str info s initial_state ~groups in let res = if st.idx = break || partial then Automata.status st.desc else let final_cat = if last = slen then Category.(search_boundary ++ inexistant) else Category.(search_boundary ++ category re ~color:(get_color re s last)) in let (idx, res) = final info st final_cat in if groups then info.positions.(idx) <- last + 1; res in match res with Automata.Match (marks, pmarks) -> Match { s ; marks; pmarks ; gpos = info.positions; gcount = re.group_count} | Automata.Failed -> Failed | Automata.Running -> Running let mk_re ~initial ~colors ~color_repr ~ncolor ~lnl ~group_count = { initial ; initial_states = []; colors; color_repr; ncolor; lnl; tbl = Automata.create_working_area (); states = Automata.State.Table.create 97; group_count } (**** Character sets ****) let cseq c c' = Cset.seq (Char.code c) (Char.code c') let cadd c s = Cset.add (Char.code c) s let trans_set cache cm s = match Cset.one_char s with | Some i -> Cset.csingle (Bytes.get cm i) | None -> let v = (Cset.hash_rec s, s) in try Cset.CSetMap.find v !cache with Not_found -> let l = Cset.fold_right s ~f:(fun (i, j) l -> Cset.union (cseq (Bytes.get cm i) (Bytes.get cm j)) l) ~init:Cset.empty in cache := Cset.CSetMap.add v l !cache; l (****) type regexp = Set of Cset.t | Sequence of regexp list | Alternative of regexp list | Repeat of regexp * int * int option | Beg_of_line | End_of_line | Beg_of_word | End_of_word | Not_bound | Beg_of_str | End_of_str | Last_end_of_line | Start | Stop | Sem of Automata.sem * regexp | Sem_greedy of Automata.rep_kind * regexp | Group of regexp | No_group of regexp | Nest of regexp | Case of regexp | No_case of regexp | Intersection of regexp list | Complement of regexp list | Difference of regexp * regexp | Pmark of Pmark.t * regexp module View = struct type t = regexp = Set of Cset.t | Sequence of regexp list | Alternative of regexp list | Repeat of regexp * int * int option | Beg_of_line | End_of_line | Beg_of_word | End_of_word | Not_bound | Beg_of_str | End_of_str | Last_end_of_line | Start | Stop | Sem of Automata.sem * regexp | Sem_greedy of Automata.rep_kind * regexp | Group of regexp | No_group of regexp | Nest of regexp | Case of regexp | No_case of regexp | Intersection of regexp list | Complement of regexp list | Difference of regexp * regexp | Pmark of Pmark.t * regexp let view t = t end let rec pp fmt t = let open Fmt in let var s re = sexp fmt s pp re in let seq s rel = sexp fmt s (list pp) rel in match t with | Set s -> sexp fmt "Set" Cset.pp s | Sequence sq -> seq "Sequence" sq | Alternative alt -> seq "Alternative" alt | Repeat (re, start, stop) -> let pp' fmt () = fprintf fmt "%a@ %d%a" pp re start optint stop in sexp fmt "Repeat" pp' () | Beg_of_line -> str fmt "Beg_of_line" | End_of_line -> str fmt "End_of_line" | Beg_of_word -> str fmt "Beg_of_word" | End_of_word -> str fmt "End_of_word" | Not_bound -> str fmt "Not_bound" | Beg_of_str -> str fmt "Beg_of_str" | End_of_str -> str fmt "End_of_str" | Last_end_of_line -> str fmt "Last_end_of_line" | Start -> str fmt "Start" | Stop -> str fmt "Stop" | Sem (sem, re) -> sexp fmt "Sem" (pair Automata.pp_sem pp) (sem, re) | Sem_greedy (k, re) -> sexp fmt "Sem_greedy" (pair Automata.pp_rep_kind pp) (k, re) | Group c -> var "Group" c | No_group c -> var "No_group" c | Nest c -> var "Nest" c | Case c -> var "Case" c | No_case c -> var "No_case" c | Intersection c -> seq "Intersection" c | Complement c -> seq "Complement" c | Difference (a, b) -> sexp fmt "Difference" (pair pp pp) (a, b) | Pmark (m, r) -> sexp fmt "Pmark" (pair Pmark.pp pp) (m, r) let rec is_charset = function | Set _ -> true | Alternative l | Intersection l | Complement l -> List.for_all is_charset l | Difference (r, r') -> is_charset r && is_charset r' | Sem (_, r) | Sem_greedy (_, r) | No_group r | Case r | No_case r -> is_charset r | Sequence _ | Repeat _ | Beg_of_line | End_of_line | Beg_of_word | End_of_word | Beg_of_str | End_of_str | Not_bound | Last_end_of_line | Start | Stop | Group _ | Nest _ | Pmark (_,_)-> false (*XXX Use a better algorithm allowing non-contiguous regions? *) let cupper = Cset.union (cseq 'A' 'Z') (Cset.union (cseq '\192' '\214') (cseq '\216' '\222')) let clower = Cset.offset 32 cupper let calpha = List.fold_right cadd ['\170'; '\181'; '\186'; '\223'; '\255'] (Cset.union clower cupper) let cdigit = cseq '0' '9' let calnum = Cset.union calpha cdigit let cword = cadd '_' calnum let colorize c regexp = let lnl = ref false in let rec colorize regexp = match regexp with Set s -> Color_map.split s c | Sequence l -> List.iter colorize l | Alternative l -> List.iter colorize l | Repeat (r, _, _) -> colorize r | Beg_of_line | End_of_line -> Color_map.split (Cset.csingle '\n') c | Beg_of_word | End_of_word | Not_bound -> Color_map.split cword c | Beg_of_str | End_of_str | Start | Stop -> () | Last_end_of_line -> lnl := true | Sem (_, r) | Sem_greedy (_, r) | Group r | No_group r | Nest r | Pmark (_,r) -> colorize r | Case _ | No_case _ | Intersection _ | Complement _ | Difference _ -> assert false in colorize regexp; !lnl (**** Compilation ****) let rec equal x1 x2 = match x1, x2 with Set s1, Set s2 -> s1 = s2 | Sequence l1, Sequence l2 -> eq_list l1 l2 | Alternative l1, Alternative l2 -> eq_list l1 l2 | Repeat (x1', i1, j1), Repeat (x2', i2, j2) -> i1 = i2 && j1 = j2 && equal x1' x2' | Beg_of_line, Beg_of_line | End_of_line, End_of_line | Beg_of_word, Beg_of_word | End_of_word, End_of_word | Not_bound, Not_bound | Beg_of_str, Beg_of_str | End_of_str, End_of_str | Last_end_of_line, Last_end_of_line | Start, Start | Stop, Stop -> true | Sem (sem1, x1'), Sem (sem2, x2') -> sem1 = sem2 && equal x1' x2' | Sem_greedy (k1, x1'), Sem_greedy (k2, x2') -> k1 = k2 && equal x1' x2' | Group _, Group _ -> (* Do not merge groups! *) false | No_group x1', No_group x2' -> equal x1' x2' | Nest x1', Nest x2' -> equal x1' x2' | Case x1', Case x2' -> equal x1' x2' | No_case x1', No_case x2' -> equal x1' x2' | Intersection l1, Intersection l2 -> eq_list l1 l2 | Complement l1, Complement l2 -> eq_list l1 l2 | Difference (x1', x1''), Difference (x2', x2'') -> equal x1' x2' && equal x1'' x2'' | Pmark (m1, r1), Pmark (m2, r2) -> Pmark.equal m1 m2 && equal r1 r2 | _ -> false and eq_list l1 l2 = match l1, l2 with [], [] -> true | x1 :: r1, x2 :: r2 -> equal x1 x2 && eq_list r1 r2 | _ -> false let sequence = function | [x] -> x | l -> Sequence l let rec merge_sequences = function | [] -> [] | Alternative l' :: r -> merge_sequences (l' @ r) | Sequence (x :: y) :: r -> begin match merge_sequences r with Sequence (x' :: y') :: r' when equal x x' -> Sequence [x; Alternative [sequence y; sequence y']] :: r' | r' -> Sequence (x :: y) :: r' end | x :: r -> x :: merge_sequences r module A = Automata let enforce_kind ids kind kind' cr = match kind, kind' with `First, `First -> cr | `First, k -> A.seq ids k cr (A.eps ids) | _ -> cr (* XXX should probably compute a category mask *) let rec translate ids kind ign_group ign_case greedy pos cache c = function | Set s -> (A.cst ids (trans_set cache c s), kind) | Sequence l -> (trans_seq ids kind ign_group ign_case greedy pos cache c l, kind) | Alternative l -> begin match merge_sequences l with [r'] -> let (cr, kind') = translate ids kind ign_group ign_case greedy pos cache c r' in (enforce_kind ids kind kind' cr, kind) | merged_sequences -> (A.alt ids (List.map (fun r' -> let (cr, kind') = translate ids kind ign_group ign_case greedy pos cache c r' in enforce_kind ids kind kind' cr) merged_sequences), kind) end | Repeat (r', i, j) -> let (cr, kind') = translate ids kind ign_group ign_case greedy pos cache c r' in let rem = match j with None -> A.rep ids greedy kind' cr | Some j -> let f = match greedy with `Greedy -> fun rem -> A.alt ids [A.seq ids kind' (A.rename ids cr) rem; A.eps ids] | `Non_greedy -> fun rem -> A.alt ids [A.eps ids; A.seq ids kind' (A.rename ids cr) rem] in iter (j - i) f (A.eps ids) in (iter i (fun rem -> A.seq ids kind' (A.rename ids cr) rem) rem, kind) | Beg_of_line -> (A.after ids Category.(inexistant ++ newline), kind) | End_of_line -> (A.before ids Category.(inexistant ++ newline), kind) | Beg_of_word -> (A.seq ids `First (A.after ids Category.(inexistant ++ not_letter)) (A.before ids Category.(inexistant ++ letter)), kind) | End_of_word -> (A.seq ids `First (A.after ids Category.(inexistant ++ letter)) (A.before ids Category.(inexistant ++ not_letter)), kind) | Not_bound -> (A.alt ids [A.seq ids `First (A.after ids Category.letter) (A.before ids Category.letter); A.seq ids `First (A.after ids Category.letter) (A.before ids Category.letter)], kind) | Beg_of_str -> (A.after ids Category.inexistant, kind) | End_of_str -> (A.before ids Category.inexistant, kind) | Last_end_of_line -> (A.before ids Category.(inexistant ++ lastnewline), kind) | Start -> (A.after ids Category.search_boundary, kind) | Stop -> (A.before ids Category.search_boundary, kind) | Sem (kind', r') -> let (cr, kind'') = translate ids kind' ign_group ign_case greedy pos cache c r' in (enforce_kind ids kind' kind'' cr, kind') | Sem_greedy (greedy', r') -> translate ids kind ign_group ign_case greedy' pos cache c r' | Group r' -> if ign_group then translate ids kind ign_group ign_case greedy pos cache c r' else let p = !pos in pos := !pos + 2; let (cr, kind') = translate ids kind ign_group ign_case greedy pos cache c r' in (A.seq ids `First (A.mark ids p) ( A.seq ids `First cr (A.mark ids (p + 1))), kind') | No_group r' -> translate ids kind true ign_case greedy pos cache c r' | Nest r' -> let b = !pos in let (cr, kind') = translate ids kind ign_group ign_case greedy pos cache c r' in let e = !pos - 1 in if e < b then (cr, kind') else (A.seq ids `First (A.erase ids b e) cr, kind') | Difference _ | Complement _ | Intersection _ | No_case _ | Case _ -> assert false | Pmark (i, r') -> let (cr, kind') = translate ids kind ign_group ign_case greedy pos cache c r' in (A.seq ids `First (A.pmark ids i) cr, kind') and trans_seq ids kind ign_group ign_case greedy pos cache c = function | [] -> A.eps ids | [r] -> let (cr', kind') = translate ids kind ign_group ign_case greedy pos cache c r in enforce_kind ids kind kind' cr' | r :: rem -> let (cr', kind') = translate ids kind ign_group ign_case greedy pos cache c r in let cr'' = trans_seq ids kind ign_group ign_case greedy pos cache c rem in if A.is_eps cr'' then cr' else if A.is_eps cr' then cr'' else A.seq ids kind' cr' cr'' (**** Case ****) let case_insens s = Cset.union s (Cset.union (Cset.offset 32 (Cset.inter s cupper)) (Cset.offset (-32) (Cset.inter s clower))) let as_set = function | Set s -> s | _ -> assert false (* XXX Should split alternatives into (1) charsets and (2) more complex regular expressions; alternative should therefore probably be flatten here *) let rec handle_case ign_case = function | Set s -> Set (if ign_case then case_insens s else s) | Sequence l -> Sequence (List.map (handle_case ign_case) l) | Alternative l -> let l' = List.map (handle_case ign_case) l in if is_charset (Alternative l') then Set (List.fold_left (fun s r -> Cset.union s (as_set r)) Cset.empty l') else Alternative l' | Repeat (r, i, j) -> Repeat (handle_case ign_case r, i, j) | Beg_of_line | End_of_line | Beg_of_word | End_of_word | Not_bound | Beg_of_str | End_of_str | Last_end_of_line | Start | Stop as r -> r | Sem (k, r) -> let r' = handle_case ign_case r in if is_charset r' then r' else Sem (k, r') | Sem_greedy (k, r) -> let r' = handle_case ign_case r in if is_charset r' then r' else Sem_greedy (k, r') | Group r -> Group (handle_case ign_case r) | No_group r -> let r' = handle_case ign_case r in if is_charset r' then r' else No_group r' | Nest r -> let r' = handle_case ign_case r in if is_charset r' then r' else Nest r' | Case r -> handle_case false r | No_case r -> handle_case true r | Intersection l -> let l' = List.map (fun r -> handle_case ign_case r) l in Set (List.fold_left (fun s r -> Cset.inter s (as_set r)) Cset.cany l') | Complement l -> let l' = List.map (fun r -> handle_case ign_case r) l in Set (Cset.diff Cset.cany (List.fold_left (fun s r -> Cset.union s (as_set r)) Cset.empty l')) | Difference (r, r') -> Set (Cset.inter (as_set (handle_case ign_case r)) (Cset.diff Cset.cany (as_set (handle_case ign_case r')))) | Pmark (i,r) -> Pmark (i,handle_case ign_case r) (****) let compile_1 regexp = let regexp = handle_case false regexp in let c = Color_map.make () in let need_lnl = colorize c regexp in let (colors, color_repr, ncolor) = Color_map.flatten c in let lnl = if need_lnl then ncolor else -1 in let ncolor = if need_lnl then ncolor + 1 else ncolor in let ids = A.create_ids () in let pos = ref 0 in let (r, kind) = translate ids `First false false `Greedy pos (ref Cset.CSetMap.empty) colors regexp in let r = enforce_kind ids `First kind r in (*Format.eprintf "<%d %d>@." !ids ncol;*) mk_re ~initial:r ~colors ~color_repr ~ncolor ~lnl ~group_count:(!pos / 2) (****) let rec anchored = function | Sequence l -> List.exists anchored l | Alternative l -> List.for_all anchored l | Repeat (r, i, _) -> i > 0 && anchored r | Set _ | Beg_of_line | End_of_line | Beg_of_word | End_of_word | Not_bound | End_of_str | Last_end_of_line | Stop | Intersection _ | Complement _ | Difference _ -> false | Beg_of_str | Start -> true | Sem (_, r) | Sem_greedy (_, r) | Group r | No_group r | Nest r | Case r | No_case r | Pmark (_, r) -> anchored r (****) type t = regexp let str s = let l = ref [] in for i = String.length s - 1 downto 0 do l := Set (Cset.csingle s.[i]) :: !l done; Sequence !l let char c = Set (Cset.csingle c) let alt = function | [r] -> r | l -> Alternative l let seq = function | [r] -> r | l -> Sequence l let empty = alt [] let epsilon = seq [] let repn r i j = if i < 0 then invalid_arg "Re.repn"; begin match j with | Some j when j < i -> invalid_arg "Re.repn" | _ -> () end; Repeat (r, i, j) let rep r = repn r 0 None let rep1 r = repn r 1 None let opt r = repn r 0 (Some 1) let bol = Beg_of_line let eol = End_of_line let bow = Beg_of_word let eow = End_of_word let word r = seq [bow; r; eow] let not_boundary = Not_bound let bos = Beg_of_str let eos = End_of_str let whole_string r = seq [bos; r; eos] let leol = Last_end_of_line let start = Start let stop = Stop let longest r = Sem (`Longest, r) let shortest r = Sem (`Shortest, r) let first r = Sem (`First, r) let greedy r = Sem_greedy (`Greedy, r) let non_greedy r = Sem_greedy (`Non_greedy, r) let group r = Group r let no_group r = No_group r let nest r = Nest r let mark r = let i = Pmark.gen () in (i,Pmark (i,r)) let set str = let s = ref Cset.empty in for i = 0 to String.length str - 1 do s := Cset.union (Cset.csingle str.[i]) !s done; Set !s let rg c c' = Set (cseq c c') let inter l = let r = Intersection l in if is_charset r then r else invalid_arg "Re.inter" let compl l = let r = Complement l in if is_charset r then r else invalid_arg "Re.compl" let diff r r' = let r'' = Difference (r, r') in if is_charset r'' then r'' else invalid_arg "Re.diff" let any = Set Cset.cany let notnl = Set (Cset.diff Cset.cany (Cset.csingle '\n')) let lower = alt [rg 'a' 'z'; char '\181'; rg '\223' '\246'; rg '\248' '\255'] let upper = alt [rg 'A' 'Z'; rg '\192' '\214'; rg '\216' '\222'] let alpha = alt [lower; upper; char '\170'; char '\186'] let digit = rg '0' '9' let alnum = alt [alpha; digit] let wordc = alt [alnum; char '_'] let ascii = rg '\000' '\127' let blank = set "\t " let cntrl = alt [rg '\000' '\031'; rg '\127' '\159'] let graph = alt [rg '\033' '\126'; rg '\160' '\255'] let print = alt [rg '\032' '\126'; rg '\160' '\255'] let punct = alt [rg '\033' '\047'; rg '\058' '\064'; rg '\091' '\096'; rg '\123' '\126'; rg '\160' '\169'; rg '\171' '\180'; rg '\182' '\185'; rg '\187' '\191'; char '\215'; char '\247'] let space = alt [char ' '; rg '\009' '\013'] let xdigit = alt [digit; rg 'a' 'f'; rg 'A' 'F'] let case r = Case r let no_case r = No_case r (****) let compile r = compile_1 ( if anchored r then group r else seq [shortest (rep any); group r] ) let exec_internal name ?(pos=0) ?(len = -1) ~partial ~groups re s = if pos < 0 || len < -1 || pos + len > String.length s then invalid_arg name; match_str ~groups ~partial re s ~pos ~len let exec ?pos ?len re s = match exec_internal "Re.exec" ?pos ?len ~groups:true ~partial:false re s with Match substr -> substr | _ -> raise Not_found let exec_opt ?pos ?len re s = match exec_internal "Re.exec_opt" ?pos ?len ~groups:true ~partial:false re s with Match substr -> Some substr | _ -> None let execp ?pos ?len re s = match exec_internal ~groups:false ~partial:false "Re.execp" ?pos ?len re s with Match _substr -> true | _ -> false let exec_partial ?pos ?len re s = match exec_internal ~groups:false ~partial:true "Re.exec_partial" ?pos ?len re s with Match _ -> `Full | Running -> `Partial | Failed -> `Mismatch module Mark = struct type t = Pmark.t let test (g : Group.t) p = Pmark.Set.mem p g.pmarks let all (g : Group.t) = g.pmarks module Set = Pmark.Set let equal = Pmark.equal let compare = Pmark.compare end type split_token = [ `Text of string | `Delim of Group.t ] module Rseq = struct let all ?(pos=0) ?len re s : _ Seq.t = if pos < 0 then invalid_arg "Re.all"; (* index of the first position we do not consider. !pos < limit is an invariant *) let limit = match len with | None -> String.length s | Some l -> if l<0 || pos+l > String.length s then invalid_arg "Re.all"; pos+l in (* iterate on matches. When a match is found, search for the next one just after its end *) let rec aux pos () = if pos >= limit then Seq.Nil (* no more matches *) else match match_str ~groups:true ~partial:false re s ~pos ~len:(limit - pos) with | Match substr -> let p1, p2 = Group.offset substr 0 in let pos = if p1=p2 then p2+1 else p2 in Seq.Cons (substr, aux pos) | Running | Failed -> Seq.Nil in aux pos let matches ?pos ?len re s : _ Seq.t = all ?pos ?len re s |> Seq.map (fun sub -> Group.get sub 0) let split_full ?(pos=0) ?len re s : _ Seq.t = if pos < 0 then invalid_arg "Re.split"; let limit = match len with | None -> String.length s | Some l -> if l<0 || pos+l > String.length s then invalid_arg "Re.split"; pos+l in (* i: start of delimited string pos: first position after last match of [re] limit: first index we ignore (!pos < limit is an invariant) *) let pos0 = pos in let rec aux state i pos () = match state with | `Idle when pos >= limit -> if i < limit then ( let sub = String.sub s i (limit - i) in Seq.Cons (`Text sub, aux state (i+1) pos) ) else Seq.Nil | `Idle -> begin match match_str ~groups:true ~partial:false re s ~pos ~len:(limit - pos) with | Match substr -> let p1, p2 = Group.offset substr 0 in let pos = if p1=p2 then p2+1 else p2 in let old_i = i in let i = p2 in if p1 > pos0 then ( (* string does not start by a delimiter *) let text = String.sub s old_i (p1 - old_i) in let state = `Yield (`Delim substr) in Seq.Cons (`Text text, aux state i pos) ) else Seq.Cons (`Delim substr, aux state i pos) | Running -> Seq.Nil | Failed -> if i < limit then ( let text = String.sub s i (limit - i) in (* yield last string *) Seq.Cons (`Text text, aux state limit pos) ) else Seq.Nil end | `Yield x -> Seq.Cons (x, aux `Idle i pos) in aux `Idle pos pos let split ?pos ?len re s : _ Seq.t = let seq = split_full ?pos ?len re s in let rec filter seq () = match seq () with | Seq.Nil -> Seq.Nil | Seq.Cons (`Delim _, tl) -> filter tl () | Seq.Cons (`Text s,tl) -> Seq.Cons (s, filter tl) in filter seq end module Rlist = struct let list_of_seq (s:'a Seq.t) : 'a list = Seq.fold_left (fun l x -> x :: l) [] s |> List.rev let all ?pos ?len re s = Rseq.all ?pos ?len re s |> list_of_seq let matches ?pos ?len re s = Rseq.matches ?pos ?len re s |> list_of_seq let split_full ?pos ?len re s = Rseq.split_full ?pos ?len re s |> list_of_seq let split ?pos ?len re s = Rseq.split ?pos ?len re s |> list_of_seq end module Gen = struct type 'a gen = unit -> 'a option let gen_of_seq (s:'a Seq.t) : 'a gen = let r = ref s in fun () -> match !r () with | Seq.Nil -> None | Seq.Cons (x, tl) -> r := tl; Some x let split ?pos ?len re s : _ gen = Rseq.split ?pos ?len re s |> gen_of_seq let split_full ?pos ?len re s : _ gen = Rseq.split_full ?pos ?len re s |> gen_of_seq let all ?pos ?len re s = Rseq.all ?pos ?len re s |> gen_of_seq let matches ?pos ?len re s = Rseq.matches ?pos ?len re s |> gen_of_seq end let replace ?(pos=0) ?len ?(all=true) re ~f s = if pos < 0 then invalid_arg "Re.replace"; let limit = match len with | None -> String.length s | Some l -> if l<0 || pos+l > String.length s then invalid_arg "Re.replace"; pos+l in (* buffer into which we write the result *) let buf = Buffer.create (String.length s) in (* iterate on matched substrings. *) let rec iter pos = if pos < limit then match match_str ~groups:true ~partial:false re s ~pos ~len:(limit-pos) with | Match substr -> let p1, p2 = Group.offset substr 0 in (* add string between previous match and current match *) Buffer.add_substring buf s pos (p1-pos); (* what should we replace the matched group with? *) let replacing = f substr in Buffer.add_string buf replacing; if all then (* if we matched a non-char e.g. ^ we must manually advance by 1 *) iter ( if p1=p2 then ( (* a non char could be past the end of string. e.g. $ *) if p2 < limit then Buffer.add_char buf s.[p2]; p2+1 ) else p2) else Buffer.add_substring buf s p2 (limit-p2) | Running -> () | Failed -> Buffer.add_substring buf s pos (limit-pos) in iter pos; Buffer.contents buf let replace_string ?pos ?len ?all re ~by s = replace ?pos ?len ?all re s ~f:(fun _ -> by) let witness t = let rec witness = function | Set c -> String.make 1 (Char.chr (Cset.pick c)) | Sequence xs -> String.concat "" (List.map witness xs) | Alternative (x :: _) -> witness x | Alternative [] -> assert false | Repeat (r, from, _to) -> let w = witness r in let b = Buffer.create (String.length w * from) in for _i=1 to from do Buffer.add_string b w done; Buffer.contents b | No_case r -> witness r | Intersection _ | Complement _ | Difference (_, _) -> assert false | Group r | No_group r | Nest r | Sem (_, r) | Pmark (_, r) | Case r | Sem_greedy (_, r) -> witness r | Beg_of_line | End_of_line | Beg_of_word | End_of_word | Not_bound | Beg_of_str | Last_end_of_line | Start | Stop | 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} *) 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 let get = Group.get let get_ofs = Group.offset let get_all = Group.all let get_all_ofs = Group.all_offset let test = Group.test type markid = Mark.t let marked = Mark.test let mark_set = Mark.all (**********************************) (* Information about the previous character: - does not exists - is a letter - is not a letter - is a newline - is last newline Beginning of word: - previous is not a letter or does not exist - current is a letter or does not exist End of word: - previous is a letter or does not exist - current is not a letter or does not exist Beginning of line: - previous is a newline or does not exist Beginning of buffer: - previous does not exist End of buffer - current does not exist End of line - current is a newline or does not exist *) (* Rep: e = T,e | () - semantics of the comma (shortest/longest/first) - semantics of the union (greedy/non-greedy) Bounded repetition a{0,3} = (a,(a,a?)?)? *) type groups = Group.t include Rlist ocaml-re-1.9.0/lib/core.mli000066400000000000000000000274011345204770300154320ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, with linking exception; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) (** Module [Re]: regular expressions commons *) type t (** Regular expression *) type re (** Compiled regular expression *) (** Manipulate matching groups. *) module Group : sig type t (** Information about groups in a match. *) val get : t -> int -> string (** Raise [Not_found] if the group did not match *) val offset : t -> int -> int * int (** Raise [Not_found] if the group did not match *) val start : t -> int -> int (** Return the start of the match. Raise [Not_found] if the group did not match. *) val stop : t -> int -> int (** Return the end of the match. Raise [Not_found] if the group did not match. *) val all : t -> string array (** Return the empty string for each group which did not match *) val all_offset : t -> (int * int) array (** Return [(-1,-1)] for each group which did not match *) val test : t -> int -> bool (** Test whether a group matched *) val nb_groups : t -> int (** Returns the total number of groups defined - matched or not. This function is experimental. *) val pp : Format.formatter -> t -> unit end type groups = Group.t [@@ocaml.deprecated "Use Group.t"] (** {2 Compilation and execution of a regular expression} *) val compile : t -> re (** Compile a regular expression into an executable version that can be used to match strings, e.g. with {!exec}. *) val exec : ?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], and returns the matched groups if any. @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 @raise Not_found if the regular expression can't be found in [str] *) val exec_opt : ?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) *) re -> string -> bool (** Similar to {!exec}, but returns [true] if the expression matches, and [false] if it doesn't *) val exec_partial : ?pos:int -> (* Default: 0 *) ?len:int -> (* Default: -1 (until end of string) *) re -> string -> [ `Full | `Partial | `Mismatch ] (** More detailed version of {!exec_p} *) (** Marks *) module Mark : sig type t (** Mark id *) val test : Group.t -> t -> bool (** Tell if a mark was matched. *) module Set : Set.S with type elt = t val all : Group.t -> Set.t (** Return all the mark matched. *) val equal : t -> t -> bool val compare : t -> t -> int end (** {2 High Level Operations} *) type split_token = [ `Text of string (** Text between delimiters *) | `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.*) type 'a gen = unit -> 'a option 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 [@@ocaml.deprecated "Use Seq.all"] val matches : ?pos:int -> ?len:int -> re -> string -> string list (** Same as {!all}, but extracts the matched substring rather than returning the whole group. This basically iterates over matched strings *) 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 [@@ocaml.deprecated "Use Seq.matches"] val split : ?pos:int -> ?len:int -> re -> string -> string list (** [split re s] splits [s] into chunks separated by [re]. It yields the chunks themselves, not the separator. For instance this can be used with a whitespace-matching re such as ["[\t ]+"]. *) 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 [@@ocaml.deprecated "Use Seq.split"] val split_full : ?pos:int -> ?len:int -> re -> string -> split_token list (** [split re s] splits [s] into chunks separated by [re]. It yields the chunks along with the separators. For instance this can be used with a whitespace-matching re such as ["[\t ]+"]. *) 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 [@@ocaml.deprecated "Use Seq.split_full"] 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 *) string -> (** string to replace in *) string (** [replace ~all re ~f s] iterates on [s], and replaces every occurrence of [re] with [f substring] where [substring] is the current match. If [all = false], then only the first occurrence of [re] is replaced. *) val replace_string : ?pos:int -> (** Default: 0 *) ?len:int -> ?all:bool -> (** Default: true. Otherwise only replace first occurrence *) re -> (** matched groups *) by:string -> (** replacement string *) string -> (** string to replace in *) string (** [replace_string ~all re ~by s] iterates on [s], and replaces every occurrence of [re] with [by]. If [all = false], then only the first occurrence of [re] is replaced. *) (** {2 String expressions (literal match)} *) val str : string -> t val char : char -> t (** {2 Basic operations on regular expressions} *) val alt : t list -> t (** Alternative *) val seq : t list -> t (** Sequence *) val empty : t (** Match nothing *) val epsilon : t (** Empty word *) val rep : t -> t (** 0 or more matches *) val rep1 : t -> t (** 1 or more matches *) val repn : t -> int -> int option -> t (** [repn re i j] matches [re] at least [i] times and at most [j] times, bounds included. [j = None] means no upper bound. *) val opt : t -> t (** 0 or 1 matches *) (** {2 String, line, word} *) val bol : t (** Beginning of line *) val eol : t (** End of line *) val bow : t (** Beginning of word *) val eow : t (** End of word *) val bos : t (** Beginning of string *) val eos : t (** End of string *) val leol : t (** Last end of line or end of string *) val start : t (** Initial position *) val stop : t (** Final position *) val word : t -> t (** Word *) val not_boundary : t (** Not at a word boundary *) val whole_string : t -> t (** Only matches the whole string *) (** {2 Match semantics} *) val longest : t -> t (** Longest match *) val shortest : t -> t (** Shortest match *) val first : t -> t (** First match *) (** {2 Repeated match modifiers} *) val greedy : t -> t (** Greedy *) val non_greedy : t -> t (** Non-greedy *) (** {2 Groups (or submatches)} *) val group : t -> t (** Delimit a group *) 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 *) val mark : t -> Mark.t * t (** Mark a regexp. the markid can then be used to know if this regexp was used. *) (** {2 Character sets} *) val set : string -> t (** Any character of the string *) val rg : char -> char -> t (** Character ranges *) val inter : t list -> t (** Intersection of character sets *) val diff : t -> t -> t (** Difference of character sets *) val compl : t list -> t (** Complement of union *) (** {2 Predefined character sets} *) val any : t (** Any character *) val notnl : t (** Any character but a newline *) val alnum : t val wordc : t val alpha : t val ascii : t val blank : t val cntrl : t val digit : t val graph : t val lower : t val print : t val punct : t val space : t val upper : t val xdigit : t (** {2 Case modifiers} *) val case : t -> t (** Case sensitive matching *) val no_case : t -> t (** Case insensitive matching *) (****) (** {2 Internal debugging} *) val pp : Format.formatter -> t -> unit val pp_re : Format.formatter -> re -> unit (** Alias for {!pp_re}. Deprecated *) val print_re : Format.formatter -> re -> unit module View : sig type outer (** A view of the top-level of a regex. This type is unstable and may change *) type t = Set of Cset.t | Sequence of outer list | Alternative of outer list | Repeat of outer * int * int option | Beg_of_line | End_of_line | Beg_of_word | End_of_word | Not_bound | Beg_of_str | End_of_str | Last_end_of_line | Start | Stop | Sem of Automata.sem * outer | Sem_greedy of Automata.rep_kind * outer | Group of outer | No_group of outer | Nest of outer | Case of outer | No_case of outer | Intersection of outer list | Complement of outer list | Difference of outer * outer | Pmark of Pmark.t * outer val view : outer -> t end with type outer := t (** {2 Experimental functions}. *) val witness : t -> string (** [witness r] generates a string [s] such that [execp (compile r) s] is true *) (** {2 Deprecated functions} *) type substrings = Group.t [@@ocaml.deprecated "Use Group.t"] (** Alias for {!Group.t}. Deprecated *) val get : Group.t -> int -> string [@@ocaml.deprecated "Use Group.get"] (** Same as {!Group.get}. Deprecated *) val get_ofs : Group.t -> int -> int * int [@@ocaml.deprecated "Use Group.offset"] (** Same as {!Group.offset}. Deprecated *) val get_all : Group.t -> string array [@@ocaml.deprecated "Use Group.all"] (** Same as {!Group.all}. Deprecated *) val get_all_ofs : Group.t -> (int * int) array [@@ocaml.deprecated "Use Group.all_offset"] (** Same as {!Group.all_offset}. Deprecated *) val test : Group.t -> int -> bool [@@ocaml.deprecated "Use Group.test"] (** Same as {!Group.test}. Deprecated *) type markid = Mark.t [@@ocaml.deprecated "Use Mark."] (** Alias for {!Mark.t}. Deprecated *) val marked : Group.t -> Mark.t -> bool [@@ocaml.deprecated "Use Mark.test"] (** Same as {!Mark.test}. Deprecated *) val mark_set : Group.t -> Mark.Set.t [@@ocaml.deprecated "Use Mark.all"] (** Same as {!Mark.all}. Deprecated *) ocaml-re-1.9.0/lib/cset.ml000066400000000000000000000072011345204770300152630ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, with linking exception; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) type c = int type t = (c * c) list let rec union l l' = match l, l' with _, [] -> l | [], _ -> l' | (c1, c2)::r, (c1', c2')::r' -> if c2 + 1 < c1' then (c1, c2)::union r l' else if c2' + 1 < c1 then (c1', c2')::union l r' else if c2 < c2' then union r ((min c1 c1', c2')::r') else union ((min c1 c1', c2)::r) r' let rec inter l l' = match l, l' with _, [] -> [] | [], _ -> [] | (c1, c2)::r, (c1', c2')::r' -> if c2 < c1' then inter r l' else if c2' < c1 then inter l r' else if c2 < c2' then (max c1 c1', c2)::inter r l' else (max c1 c1', c2')::inter l r' let rec diff l l' = match l, l' with _, [] -> l | [], _ -> [] | (c1, c2)::r, (c1', c2')::r' -> if c2 < c1' then (c1, c2)::diff r l' else if c2' < c1 then diff l r' else let r'' = if c2' < c2 then (c2' + 1, c2) :: r else r in if c1 < c1' then (c1, c1' - 1)::diff r'' r' else diff r'' r' let single c = [c, c] let add c l = union (single c) l let seq c c' = if c <= c' then [c, c'] else [c', c] let rec offset o l = match l with [] -> [] | (c1, c2) :: r -> (c1 + o, c2 + o) :: offset o r let empty = [] let rec mem (c : int) s = match s with [] -> false | (c1, c2) :: rem -> if c <= c2 then c >= c1 else mem c rem (****) type hash = int let rec hash_rec = function | [] -> 0 | (i, j)::r -> i + 13 * j + 257 * hash_rec r let hash l = (hash_rec l) land 0x3FFFFFFF (****) let print_one ch (c1, c2) = if c1 = c2 then Format.fprintf ch "%d" c1 else Format.fprintf ch "%d-%d" c1 c2 let pp = Fmt.list print_one let rec iter t ~f = match t with | [] -> () | (x, y)::xs -> f x y; iter xs ~f let one_char = function | [i, j] when i = j -> Some i | _ -> None module CSetMap = Map.Make (struct type t = int * (int * int) list let compare (i, u) (j, v) = let c = compare i j in if c <> 0 then c else compare u v end) let fold_right t ~init ~f = List.fold_right f t init let csingle c = single (Char.code c) let cany = [0, 255] let is_empty = function | [] -> true | _ -> false let rec prepend s x l = match s, l with | [], _ -> l | _r, [] -> [] | (_c, c') :: r, ([d, _d'], _x') :: _r' when c' < d -> prepend r x l | (c, c') :: r, ([d, d'], x') :: r' -> if c <= d then begin if c' < d' then ([d, c'], x @ x') :: prepend r x (([c' + 1, d'], x') :: r') else ([d, d'], x @ x') :: prepend s x r' end else begin if c > d' then ([d, d'], x') :: prepend s x r' else ([d, c - 1], x') :: prepend s x (([c, d'], x') :: r') end | _ -> assert false let pick = function | [] -> invalid_arg "Re_cset.pick" | (x, _)::_ -> x ocaml-re-1.9.0/lib/cset.mli000066400000000000000000000031241345204770300154340ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, with linking exception; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) (* Character sets, represented as sorted list of intervals *) type c = int type t val iter : t -> f:(c -> c -> unit) -> unit val union : t -> t -> t val inter : t -> t -> t val diff : t -> t -> t val offset : int -> t -> t val empty : t val single : c -> t val seq : c -> c -> t val add : c -> t -> t val mem : c -> t -> bool type hash val hash : t -> hash val pp : Format.formatter -> t -> unit val one_char : t -> c option val fold_right : t -> init:'acc -> f:(c * c -> 'acc -> 'acc) -> 'acc val hash_rec : t -> int module CSetMap : Map.S with type key = int * t val cany : t val csingle : char -> t val is_empty : t -> bool val prepend : t -> 'a list -> (t * 'a list) list -> (t * 'a list) list val pick : t -> c ocaml-re-1.9.0/lib/dune000066400000000000000000000001541345204770300146510ustar00rootroot00000000000000(library (name re) (synopsis "Pure OCaml regular expression library") (libraries seq) (public_name re)) ocaml-re-1.9.0/lib/emacs.ml000066400000000000000000000073701345204770300154240ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, with linking exception; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) module Re = Core exception Parse_error exception Not_supported let parse s = let i = ref 0 in let l = String.length s in let eos () = !i = l in let test c = not (eos ()) && s.[!i] = c in let test2 c c' = !i + 1 < l && s.[!i] = c && s.[!i + 1] = c' in let accept c = let r = test c in if r then incr i; r in let accept2 c c' = let r = test2 c c' in if r then i := !i + 2; r in let get () = let r = s.[!i] in incr i; r in let rec regexp () = regexp' (branch ()) and regexp' left = if accept2 '\\' '|' then regexp' (Re.alt [left; branch ()]) else left and branch () = branch' [] and branch' left = if eos () || test2 '\\' '|' || test2 '\\' ')' then Re.seq (List.rev left) else branch' (piece () :: left) and piece () = let r = atom () in if accept '*' then Re.rep r else if accept '+' then Re.rep1 r else if accept '?' then Re.opt r else r and atom () = if accept '.' then begin Re.notnl end else if accept '^' then begin Re.bol end else if accept '$' then begin Re.eol end else if accept '[' then begin if accept '^' then Re.compl (bracket []) else Re.alt (bracket []) end else if accept '\\' then begin if accept '(' then begin let r = regexp () in if not (accept2 '\\' ')') then raise Parse_error; Re.group r end else if accept '`' then Re.bos else if accept '\'' then Re.eos else if accept '=' then Re.start else if accept 'b' then Re.alt [Re.bow; Re.eow] else if accept 'B' then Re.not_boundary else if accept '<' then Re.bow else if accept '>' then Re.eow else if accept 'w' then Re.alt [Re.alnum; Re.char '_'] else if accept 'W' then Re.compl [Re.alnum; Re.char '_'] else begin if eos () then raise Parse_error; match get () with '*' | '+' | '?' | '[' | ']' | '.' | '^' | '$' | '\\' as c -> Re.char c | '0' .. '9' -> raise Not_supported | _ -> raise Parse_error end end else begin if eos () then raise Parse_error; match get () with '*' | '+' | '?' -> raise Parse_error | c -> Re.char c end and bracket s = if s <> [] && accept ']' then s else begin let c = char () in if accept '-' then begin if accept ']' then Re.char c :: Re.char '-' :: s else begin let c' = char () in bracket (Re.rg c c' :: s) end end else bracket (Re.char c :: s) end and char () = if eos () then raise Parse_error; get () in let res = regexp () in if not (eos ()) then raise Parse_error; res let re ?(case = true) s = let r = parse s in if case then r else Re.no_case r let compile = Re.compile let compile_pat ?(case = true) s = compile (re ~case s) ocaml-re-1.9.0/lib/emacs.mli000066400000000000000000000024211345204770300155650ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, with linking exception; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) (** Emacs-style regular expressions *) exception Parse_error exception Not_supported (** Errors that can be raised during the parsing of the regular expression *) val re : ?case:bool -> string -> Core.t (** Parsing of an Emacs-style regular expression *) val compile : Core.t -> Core.re (** Regular expression compilation *) val compile_pat : ?case:bool -> string -> Core.re (** Same as [Core.compile] *) ocaml-re-1.9.0/lib/fmt.ml000066400000000000000000000022551345204770300151170ustar00rootroot00000000000000(** Very small tooling for format printers. *) include Format type 'a t = Format.formatter -> 'a -> unit (* Only in the stdlib since 4.02, so we copy. *) let rec list ?(pp_sep = pp_print_cut) pp ppf = function | [] -> () | [v] -> pp ppf v | v :: vs -> pp ppf v; pp_sep ppf (); list ~pp_sep pp ppf vs (* want this name to make sure we don't use pp_print_list from stdlib accidentally *) let pp_print_list = list let str = pp_print_string let sexp fmt s pp x = fprintf fmt "@[<3>(%s@ %a)@]" s pp x let pair pp1 pp2 fmt (v1,v2) = pp1 fmt v1; pp_print_space fmt () ; pp2 fmt v2 let triple pp1 pp2 pp3 fmt (v1, v2, v3) = pp1 fmt v1; pp_print_space fmt () ; pp2 fmt v2; pp_print_space fmt () ; pp3 fmt v3 let int = pp_print_int let optint fmt = function | None -> () | Some i -> fprintf fmt "@ %d" i let quote fmt s = Format.fprintf fmt "\"%s\"" s let pp_olist pp_elem fmt = Format.fprintf fmt "@[<3>[@ %a@ ]@]" (pp_print_list ~pp_sep:(fun fmt () -> fprintf fmt ";@ ") pp_elem) let pp_str_list = pp_olist quote let to_to_string pp x = let b = Buffer.create 16 in let fmt = Format.formatter_of_buffer b in pp fmt x; Buffer.contents b ocaml-re-1.9.0/lib/glob.ml000066400000000000000000000201351345204770300152510ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, with linking exception; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) module Re = Core exception Parse_error type enclosed = | Char of char | Range of char * char type piece = | Exactly of char | Any_of of enclosed list | Any_but of enclosed list | One | Many type t = piece list let of_string s : t = let i = ref 0 in let l = String.length s in let eos () = !i = l in let read c = let r = not (eos ()) && s.[!i] = c in if r then incr i; r in let char () = ignore (read '\\' : bool); if eos () then raise Parse_error; let r = s.[!i] in incr i; r in let enclosed () : enclosed list = let rec loop s = (* This returns the list in reverse order, but order isn't important anyway *) if s <> [] && read ']' then s else let c = char () in if not (read '-') then loop (Char c :: s) else if read ']' then Char c :: Char '-' :: s else let c' = char () in loop (Range (c, c') :: s) in loop [] in let piece () = if read '*' then Many else if read '?' then One else if not (read '[') then Exactly (char ()) else if read '^' || read '!' then Any_but (enclosed ()) else Any_of (enclosed ()) in let rec loop pieces = if eos () then List.rev pieces else loop (piece () :: pieces) in loop [] let mul l l' = List.flatten (List.map (fun s -> List.map (fun s' -> s ^ s') l') l) let explode str = let l = String.length str in let rec expl inner s i acc beg = if i >= l then begin if inner then raise Parse_error; (mul beg [String.sub str s (i - s)], i) end else match str.[i] with | '\\' -> expl inner s (i + 2) acc beg | '{' -> let (t, i') = expl true (i + 1) (i + 1) [] [""] in expl inner i' i' acc (mul beg (mul [String.sub str s (i - s)] t)) | ',' when inner -> expl inner (i + 1) (i + 1) (mul beg [String.sub str s (i - s)] @ acc) [""] | '}' when inner -> (mul beg [String.sub str s (i - s)] @ acc, i + 1) | _ -> expl inner s (i + 1) acc beg in List.rev (fst (expl false 0 0 [] [""])) module State = struct type t = { re_pieces : Re.t list; (* last piece at head of list. *) remaining : piece list; (* last piece at tail of list. *) am_at_start_of_pattern : bool; (* true at start of pattern *) am_at_start_of_component : bool; (* true at start of pattern or immediately after '/' *) pathname : bool; period : bool; } let create ~period ~pathname remaining = { re_pieces = []; am_at_start_of_pattern = true; am_at_start_of_component = true; pathname; period; remaining; } let explicit_period t = t.period && ( t.am_at_start_of_pattern || (t.am_at_start_of_component && t.pathname) ) let explicit_slash t = t.pathname let append ?(am_at_start_of_component=false) t piece = { t with re_pieces = piece :: t.re_pieces; am_at_start_of_pattern = false; am_at_start_of_component; } let to_re t = Re.seq (List.rev t.re_pieces) let next t = match t.remaining with | [] -> None | piece :: remaining -> Some (piece, { t with remaining }) end let one ~explicit_slash ~explicit_period = Re.compl ( List.concat [ if explicit_slash then [Re.char '/'] else []; if explicit_period then [Re.char '.'] else []; ] ) let enclosed enclosed = match enclosed with | Char c -> Re.char c | Range (low, high) -> Re.rg low high let enclosed_set ~explicit_slash ~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] let exactly state c = State.append state (Re.char c) ~am_at_start_of_component:(c = '/') let many (state : State.t) = let explicit_slash = State.explicit_slash state in let explicit_period = State.explicit_period 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)) 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); ] )) end else begin let not_empty = Re.seq [ one ~explicit_slash:true ~explicit_period:true; Re.rep (one ~explicit_slash:true ~explicit_period:false); ] in (* [maybe_empty] is the default translation of Many, except in some special cases. *) 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; Re.seq [ not_empty; (* Since [not_empty] matched, subsequent dots are not leading. *) enclosed_set kind set ~explicit_slash:true ~explicit_period:false; ]; ]) in let rec lookahead state = match State.next state with | None -> State.append state maybe_empty (* glob ** === glob * . *) | Some (Many, state) -> lookahead state | Some (Exactly c, state) -> let state = State.append state (if c = '.' then not_empty else maybe_empty) in exactly state c (* glob *? === glob ?* *) | 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 in lookahead state end let piece state piece = let explicit_slash = State.explicit_slash state in let explicit_period = State.explicit_period state in match piece with | One -> State.append state (one ~explicit_slash ~explicit_period) | Many -> many state | Any_of enclosed -> State.append state (enclosed_set `Any_of ~explicit_slash ~explicit_period enclosed) | Any_but enclosed -> State.append state (enclosed_set `Any_but ~explicit_slash ~explicit_period enclosed) | Exactly c -> exactly state c let glob ~pathname ~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) let glob ?(anchored = false) ?(pathname = true) ?(period = true) ?(expand_braces = false) s = let to_re s = let re = glob ~pathname ~period (of_string s) in if anchored then Re.whole_string re else re in if expand_braces then Re.alt (List.map to_re (explode s)) else to_re s let glob' ?anchored period s = glob ?anchored ~period s let globx ?anchored s = glob ?anchored ~expand_braces:true s let globx' ?anchored period s = glob ?anchored ~expand_braces:true ~period s ocaml-re-1.9.0/lib/glob.mli000066400000000000000000000057041345204770300154270ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, with linking exception; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) (** Shell-style regular expressions *) exception Parse_error val glob : ?anchored:bool -> ?pathname:bool -> ?period:bool -> ?expand_braces:bool -> string -> Core.t (** Implements the semantics of shells patterns. The returned regular expression is unanchored by default. Character '*' matches any sequence of characters and character '?' matches a single character. A sequence '[...]' matches any one of the enclosed characters. A sequence '[^...]' or '[!...]' matches any character *but* the enclosed characters. A backslash escapes the following character. The last character of the string cannot be a backslash. [anchored] controls whether the regular expression will only match entire strings. Defaults to false. [pathname]: If this flag is set, match a slash in string only with a slash in pattern and not by an asterisk ('*') or a question mark ('?') metacharacter, nor by a bracket expression ('[]') containing a slash. Defaults to true. [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 slash. Defaults to true. 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. *) val glob' : ?anchored:bool -> bool -> string -> Core.t (** Same, but allows to choose whether dots at the beginning of a file name need to be explicitly matched (true) or not (false) @deprecated Use [glob ~period]. *) val globx : ?anchored:bool -> string -> Core.t (** This version of [glob] also recognizes the pattern \{..,..\} @deprecated Prefer [glob ~expand_braces:true]. *) val globx' : ?anchored:bool -> bool -> string -> Core.t (** This version of [glob'] also recognizes the pattern \{..,..\} @deprecated Prefer [glob ~expand_braces:true ~period]. *) ocaml-re-1.9.0/lib/group.ml000066400000000000000000000032631345204770300154650ustar00rootroot00000000000000(* Result of a successful match. *) type t = { s : string ; marks : Automata.mark_infos ; pmarks : Pmark.Set.t ; gpos : int array ; gcount : int } let offset t i = if 2 * i + 1 >= Array.length t.marks then raise Not_found; let m1 = t.marks.(2 * i) in if m1 = -1 then raise Not_found; let p1 = t.gpos.(m1) - 1 in let p2 = t.gpos.(t.marks.(2 * i + 1)) - 1 in (p1, p2) let get t i = let (p1, p2) = offset t i in String.sub t.s p1 (p2 - p1) let start subs i = fst (offset subs i) let stop subs i = snd (offset subs i) let test t i = if 2 * i >= Array.length t.marks then false else let idx = t.marks.(2 * i) in idx <> -1 let dummy_offset = (-1, -1) let all_offset t = let res = Array.make t.gcount dummy_offset in for i = 0 to Array.length t.marks / 2 - 1 do let m1 = t.marks.(2 * i) in if m1 <> -1 then begin let p1 = t.gpos.(m1) in let p2 = t.gpos.(t.marks.(2 * i + 1)) in res.(i) <- (p1 - 1, p2 - 1) end done; res let dummy_string = "" let all t = let res = Array.make t.gcount dummy_string in for i = 0 to Array.length t.marks / 2 - 1 do let m1 = t.marks.(2 * i) in if m1 <> -1 then begin let p1 = t.gpos.(m1) in let p2 = t.gpos.(t.marks.(2 * i + 1)) in res.(i) <- String.sub t.s (p1 - 1) (p2 - p1) end done; res let pp fmt t = let matches = let offsets = all_offset t in let strs = all t in Array.to_list ( Array.init (Array.length strs) (fun i -> strs.(i), offsets.(i)) ) in let open Fmt in let pp_match fmt (str, (start, stop)) = fprintf fmt "@[(%s (%d %d))@]" str start stop in sexp fmt "Group" (list pp_match) matches let nb_groups t = t.gcount ocaml-re-1.9.0/lib/group.mli000066400000000000000000000031741345204770300156370ustar00rootroot00000000000000(* Result of a successful match. *) type t = { s : string (* Input string. Matched strings are substrings of s *) ; marks : Automata.mark_infos (* Mapping from group indices to positions in gpos. group i has positions 2*i - 1, 2*i + 1 in gpos. If the group wasn't matched, then its corresponding values in marks will be -1,-1 *) ; pmarks : Pmark.Set.t (* Marks positions. i.e. those marks created with Re.marks *) ; gpos : int array (* Group positions. Adjacent elements are (start, stop) of group match. indexed by the values in marks. So group i in an re would be the substring: start = t.gpos.(marks.(2*i)) - 1 stop = t.gpos.(marks.(2*i + 1)) - 1 *) ; gcount : int (* Number of groups the regular expression contains. Matched or not *) } (** Information about groups in a match. *) val get : t -> int -> string (** Raise [Not_found] if the group did not match *) val offset : t -> int -> int * int (** Raise [Not_found] if the group did not match *) val start : t -> int -> int (** Return the start of the match. Raise [Not_found] if the group did not match. *) val stop : t -> int -> int (** Return the end of the match. Raise [Not_found] if the group did not match. *) val all : t -> string array (** Return the empty string for each group which did not match *) val all_offset : t -> (int * int) array (** Return [(-1,-1)] for each group which did not match *) val test : t -> int -> bool (** Test whether a group matched *) val nb_groups : t -> int (** Returns the total number of groups defined - matched or not. This function is experimental. *) val pp : Format.formatter -> t -> unit ocaml-re-1.9.0/lib/pcre.ml000066400000000000000000000056451345204770300152700ustar00rootroot00000000000000module Re = Core type regexp = Re.re type flag = [ `CASELESS | `MULTILINE | `ANCHORED ] type split_result = | Text of string | Delim of string | Group of int * string | NoGroup type groups = Core.Group.t let re ?(flags = []) pat = let opts = List.map (function | `CASELESS -> `Caseless | `MULTILINE -> `Multiline | `ANCHORED -> `Anchored ) flags in Perl.re ~opts pat let regexp ?flags pat = Re.compile (re ?flags pat) let extract ~rex s = Re.Group.all (Re.exec rex s) let exec ~rex ?pos s = Re.exec rex ?pos s let get_substring s i = Re.Group.get s i let get_substring_ofs s i = Re.Group.offset s i let pmatch ~rex s = Re.execp rex s let substitute ~rex ~subst str = let b = Buffer.create 1024 in let rec loop pos = if pos >= String.length str then Buffer.contents b else if Re.execp ~pos rex str then ( let ss = Re.exec ~pos rex str in let start, fin = Re.Group.offset ss 0 in let pat = Re.Group.get ss 0 in Buffer.add_substring b str pos (start - pos); Buffer.add_string b (subst pat); loop fin ) else ( Buffer.add_substring b str pos (String.length str - pos); loop (String.length str) ) in loop 0 let split ~rex str = let rec loop accu pos = if pos >= String.length str then List.rev accu else if Re.execp ~pos rex str then ( let ss = Re.exec ~pos rex str in let start, fin = Re.Group.offset ss 0 in let s = String.sub str pos (start - pos) in loop (s :: accu) fin ) else ( let s = String.sub str pos (String.length str - pos) in loop (s :: accu) (String.length str) ) in loop [] 0 (* From PCRE *) let string_unsafe_sub s ofs len = let r = Bytes.create len in Bytes.unsafe_blit s ofs r 0 len; Bytes.unsafe_to_string r let quote s = let len = String.length s in let buf = Bytes.create (len lsl 1) in let pos = ref 0 in for i = 0 to len - 1 do match String.unsafe_get s i with | '\\' | '^' | '$' | '.' | '[' | '|' | '(' | ')' | '?' | '*' | '+' | '{' as c -> Bytes.unsafe_set buf !pos '\\'; incr pos; Bytes.unsafe_set buf !pos c; incr pos | c -> Bytes.unsafe_set buf !pos c; incr pos done; string_unsafe_sub buf 0 !pos let full_split ?(max=0) ~rex s = if String.length s = 0 then [] else if max = 1 then [Text s] else let results = Re.split_full rex s in let matches = List.map (function | `Text s -> [Text s] | `Delim d -> let matches = Re.Group.all_offset d in let delim = Re.Group.get d 0 in (Delim delim)::( let l = ref [] in for i = 1 to Array.length matches - 1 do l := (if matches.(i) = (-1, -1) then NoGroup else Group (i, Re.Group.get d i)) ::(!l) done; List.rev !l)) results in List.concat matches type substrings = Group.t ocaml-re-1.9.0/lib/pcre.mli000066400000000000000000000026251345204770300154340ustar00rootroot00000000000000type regexp = Core.re type flag = [ `CASELESS | `MULTILINE | `ANCHORED ] type groups = Core.Group.t (** Result of a {!Pcre.full_split} *) type split_result = | Text of string (** Text part of splitted string *) | Delim of string (** Delimiter part of splitted string *) | Group of int * string (** Subgroup of matched delimiter (subgroup_nr, subgroup_str) *) | NoGroup (** Unmatched subgroup *) val re : ?flags:(flag list) -> string -> Core.t (** [re ~flags s] creates the regexp [s] using the pcre syntax. *) val regexp : ?flags:(flag list) -> string -> regexp (** [re ~flags s] compiles the regexp [s] using the pcre syntax. *) val extract : rex:regexp -> string -> string array (** [extract ~rex s] executes [rex] on [s] and returns the matching groups. *) val exec : rex:regexp -> ?pos:int -> string -> groups (** Equivalent to {!Core.exec}. *) val get_substring : groups -> int -> string (** Equivalent to {!Core.Group.get}. *) val get_substring_ofs : groups -> int -> int * int (** Equivalent to {!Core.Group.offset}. *) val pmatch : rex:regexp -> string -> bool (** Equivalent to {!Core.execp}. *) val substitute : rex:Core.re -> subst:(string -> string) -> string -> string val full_split : ?max:int -> rex:regexp -> string -> split_result list val split : rex:regexp -> string -> string list val quote : string -> string (** {2 Deprecated} *) type substrings = Group.t ocaml-re-1.9.0/lib/perl.ml000066400000000000000000000176521345204770300153020ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, with linking exception; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) module Re = Core exception Parse_error exception Not_supported let posix_class_of_string = function | "alnum" -> Re.alnum | "ascii" -> Re.ascii | "blank" -> Re.blank | "cntrl" -> Re.cntrl | "digit" -> Re.digit | "lower" -> Re.lower | "print" -> Re.print | "space" -> Re.space | "upper" -> Re.upper | "word" -> Re.wordc | "punct" -> Re.punct | "graph" -> Re.graph | "xdigit" -> Re.xdigit | class_ -> invalid_arg ("Invalid pcre class: " ^ class_) let posix_class_strings = [ "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 let l = String.length s in let eos () = !i = l in let test c = not (eos ()) && s.[!i] = c in let accept c = let r = test c in if r then incr i; r in let accept_s s' = let len = String.length s' in try for j = 0 to len - 1 do try if s'.[j] <> s.[!i + j] then raise Exit with _ -> raise Exit done; i := !i + len; true with Exit -> false in let get () = let r = s.[!i] in incr i; r in let unget () = decr i in let greedy_mod r = let gr = accept '?' in let gr = if ungreedy then not gr else gr in if gr then Re.non_greedy r else Re.greedy r in let rec regexp () = regexp' (branch ()) and regexp' left = if accept '|' then regexp' (Re.alt [left; branch ()]) else left and branch () = branch' [] and branch' left = if eos () || test '|' || test ')' then Re.seq (List.rev left) else branch' (piece () :: left) and piece () = let r = atom () in if accept '*' then greedy_mod (Re.rep r) else if accept '+' then greedy_mod (Re.rep1 r) else if accept '?' then greedy_mod (Re.opt r) else if accept '{' then match integer () with Some i -> let j = if accept ',' then integer () else Some i in if not (accept '}') then raise Parse_error; begin match j with Some j when j < i -> raise Parse_error | _ -> () end; greedy_mod (Re.repn r i j) | None -> unget (); r else r and atom () = if accept '.' then begin if dotall then Re.any else Re.notnl end else if accept '(' then begin if accept '?' then begin if accept ':' then begin let r = regexp () in if not (accept ')') then raise Parse_error; r end else if accept '#' then begin comment () end else raise Parse_error end else begin let r = regexp () in if not (accept ')') then raise Parse_error; Re.group r end end else if accept '^' then begin if multiline then Re.bol else Re.bos end else if accept '$' then begin if multiline then Re.eol else if dollar_endonly then Re.leol else Re.eos end else if accept '[' then begin if accept '^' then Re.compl (bracket []) else Re.alt (bracket []) end else if accept '\\' then begin (* XXX - Back-references - \cx (control-x), \e, \f, \n, \r, \t, \xhh, \ddd *) if eos () then raise Parse_error; match get () with 'w' -> Re.alt [Re.alnum; Re.char '_'] | 'W' -> Re.compl [Re.alnum; Re.char '_'] | 's' -> Re.space | 'S' -> Re.compl [Re.space] | 'd' -> Re.digit | 'D' -> Re.compl [Re.digit] | 'b' -> Re.alt [Re.bow; Re.eow] | 'B' -> Re.not_boundary | 'A' -> Re.bos | 'Z' -> Re.leol | 'z' -> Re.eos | 'G' -> Re.start | 'a'..'z' | 'A'..'Z' -> raise Parse_error | '0'..'9' -> raise Not_supported | c -> Re.char c end else begin if eos () then raise Parse_error; match get () with '*' | '+' | '?' | '{' | '\\' -> raise Parse_error | c -> Re.char c end and integer () = if eos () then None else match get () with '0'..'9' as d -> integer' (Char.code d - Char.code '0') | _ -> unget (); None and integer' i = if eos () then Some i else match get () with '0'..'9' as d -> let i' = 10 * i + (Char.code d - Char.code '0') in if i' < i then raise Parse_error; integer' i' | _ -> unget (); Some i and bracket s = if s <> [] && accept ']' then s else begin match char () with | `Char c -> if accept '-' then begin if accept ']' then Re.char c :: Re.char '-' :: s else begin match char () with `Char c' -> bracket (Re.rg c c' :: s) | `Set st' -> bracket (Re.char c :: Re.char '-' :: st' :: s) end end else bracket (Re.char c :: s) | `Set st -> bracket (st :: s) end and char () = if eos () then raise Parse_error; let c = get () in if c = '[' then begin if accept '=' then raise Not_supported; if accept ':' then let compl = accept '^' in let cls = try List.find accept_s posix_class_strings with Not_found -> raise Parse_error in if not (accept_s ":]") then raise Parse_error; let re = let posix_class = posix_class_of_string cls in if compl then Re.compl [posix_class] else posix_class in `Set (re) else if accept '.' then begin if eos () then raise Parse_error; let c = get () in if not (accept '.') then raise Not_supported; if not (accept ']') then raise Parse_error; `Char c end else `Char c end else if c = '\\' then begin if eos () then raise Parse_error; let c = get () in (* XXX \127, ... *) match c with 'b' -> `Char '\008' | 'n' -> `Char '\n' (*XXX*) | 'r' -> `Char '\r' (*XXX*) | 't' -> `Char '\t' (*XXX*) | 'w' -> `Set (Re.alt [Re.alnum; Re.char '_']) | 'W' -> `Set (Re.compl [Re.alnum; Re.char '_']) | 's' -> `Set (Re.space) | 'S' -> `Set (Re.compl [Re.space]) | 'd' -> `Set (Re.digit) | 'D' -> `Set (Re.compl [Re.digit]) | 'a'..'z' | 'A'..'Z' -> raise Parse_error | '0'..'9' -> raise Not_supported | _ -> `Char c end else `Char c and comment () = if eos () then raise Parse_error; if accept ')' then Re.epsilon else begin incr i; comment () end in let res = regexp () in if not (eos ()) then raise Parse_error; res type opt = [ `Ungreedy | `Dotall | `Dollar_endonly | `Multiline | `Anchored | `Caseless ] let re ?(opts = []) s = let r = parse (List.memq `Multiline opts) (List.memq `Dollar_endonly opts) (List.memq `Dotall opts) (List.memq `Ungreedy opts) s in let r = if List.memq `Anchored opts then Re.seq [Re.start; r] else r in let r = if List.memq `Caseless opts then Re.no_case r else r in r let compile = Re.compile let compile_pat ?(opts = []) s = compile (re ~opts s) ocaml-re-1.9.0/lib/perl.mli000066400000000000000000000025651345204770300154500ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, with linking exception; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) (** Perl-style regular expressions *) exception Parse_error exception Not_supported (** Errors that can be raised during the parsing of the regular expression *) type opt = [ `Ungreedy | `Dotall | `Dollar_endonly | `Multiline | `Anchored | `Caseless ] val re : ?opts:opt list -> string -> Core.t (** Parsing of a Perl-style regular expression *) val compile : Core.t -> Core.re (** (Same as [Re.compile]) *) val compile_pat : ?opts:opt list -> string -> Core.re (** Regular expression compilation *) ocaml-re-1.9.0/lib/pmark.ml000066400000000000000000000003711345204770300154400ustar00rootroot00000000000000 module Pmark = struct type t = int let equal (x : int) (y : int) = x = y let compare (x : int) (y : int) = compare x y let r = ref 0 let gen () = incr r ; !r let pp = Format.pp_print_int end include Pmark module Set = Set.Make(Pmark) ocaml-re-1.9.0/lib/pmark.mli000066400000000000000000000002561345204770300156130ustar00rootroot00000000000000 type t = private int val equal : t -> t -> bool val compare : t -> t -> int val gen : unit -> t val pp : Format.formatter -> t -> unit module Set : Set.S with type elt = t ocaml-re-1.9.0/lib/posix.ml000066400000000000000000000116021345204770300154670ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, with linking exception; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) (* What we could (should?) do: - a* ==> longest ((shortest (no_group a)* ), a | ()) (!!!) - abc understood as (ab)c - "((a?)|b)" against "ab" should not bind the first subpattern to anything Note that it should be possible to handle "(((ab)c)d)e" efficiently *) module Re = Core exception Parse_error exception Not_supported let parse newline s = let i = ref 0 in let l = String.length s in let eos () = !i = l in let test c = not (eos ()) && s.[!i] = c in let accept c = let r = test c in if r then incr i; r in let get () = let r = s.[!i] in incr i; r in let unget () = decr i in let rec regexp () = regexp' (branch ()) and regexp' left = if accept '|' then regexp' (Re.alt [left; branch ()]) else left and branch () = branch' [] and branch' left = if eos () || test '|' || test ')' then Re.seq (List.rev left) else branch' (piece () :: left) and piece () = let r = atom () in if accept '*' then Re.rep (Re.nest r) else if accept '+' then Re.rep1 (Re.nest r) else if accept '?' then Re.opt r else if accept '{' then match integer () with Some i -> let j = if accept ',' then integer () else Some i in if not (accept '}') then raise Parse_error; begin match j with Some j when j < i -> raise Parse_error | _ -> () end; Re.repn (Re.nest r) i j | None -> unget (); r else r and atom () = if accept '.' then begin if newline then Re.notnl else Re.any end else if accept '(' then begin let r = regexp () in if not (accept ')') then raise Parse_error; Re.group r end else if accept '^' then begin if newline then Re.bol else Re.bos end else if accept '$' then begin if newline then Re.eol else Re.eos end else if accept '[' then begin if accept '^' then Re.diff (Re.compl (bracket [])) (Re.char '\n') else Re.alt (bracket []) end else if accept '\\' then begin if eos () then raise Parse_error; match get () with '|' | '(' | ')' | '*' | '+' | '?' | '[' | '.' | '^' | '$' | '{' | '\\' as c -> Re.char c | _ -> raise Parse_error end else begin if eos () then raise Parse_error; match get () with '*' | '+' | '?' | '{' | '\\' -> raise Parse_error | c -> Re.char c end and integer () = if eos () then None else match get () with '0'..'9' as d -> integer' (Char.code d - Char.code '0') | _ -> unget (); None and integer' i = if eos () then Some i else match get () with '0'..'9' as d -> let i' = 10 * i + (Char.code d - Char.code '0') in if i' < i then raise Parse_error; integer' i' | _ -> unget (); Some i and bracket s = if s <> [] && accept ']' then s else begin let c = char () in if accept '-' then begin if accept ']' then Re.char c :: Re.char '-' :: s else begin let c' = char () in bracket (Re.rg c c' :: s) end end else bracket (Re.char c :: s) end and char () = if eos () then raise Parse_error; let c = get () in if c = '[' then begin if accept '=' then raise Not_supported else if accept ':' then begin raise Not_supported (*XXX*) end else if accept '.' then begin if eos () then raise Parse_error; let c = get () in if not (accept '.') then raise Not_supported; if not (accept ']') then raise Parse_error; c end else c end else c in let res = regexp () in if not (eos ()) then raise Parse_error; res type opt = [`ICase | `NoSub | `Newline] let re ?(opts = []) s = let r = parse (List.memq `Newline opts) s in let r = if List.memq `ICase opts then Re.no_case r else r in let r = if List.memq `NoSub opts then Re.no_group r else r in r let compile re = Re.compile (Re.longest re) let compile_pat ?(opts = []) s = compile (re ~opts s) ocaml-re-1.9.0/lib/posix.mli000066400000000000000000000067771345204770300156610ustar00rootroot00000000000000(* RE - A regular expression library Copyright (C) 2001 Jerome Vouillon email: Jerome.Vouillon@pps.jussieu.fr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, with linking exception; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *) (** References: - {{: http://www.opengroup.org/onlinepubs/007908799/xbd/re.html} re} - {{: http://www.opengroup.org/onlinepubs/007908799/xsh/regcomp.html} regcomp} Example of how to use this module (to parse some IRC logs): {[ type msg = { time:string; author:string; content:string; } let re = Core.compile (Re_posix.re "([^:].*:[^:]*:[^:]{2})<.([^>]+)> (.+)$") (* parse a line *) let match_line line = try let substrings = Core.exec re line in let groups = Core.get_all substrings in (* groups can be obtained directly by index within [substrings] *) Some {time=groups.(1); author=groups.(2); content=groups.(3)} with Not_found -> None (* regex didn't match *) ]} *) (** XXX Character classes *) exception Parse_error exception Not_supported (** Errors that can be raised during the parsing of the regular expression *) type opt = [`ICase | `NoSub | `Newline] val re : ?opts:(opt list) -> string -> Core.t (** Parsing of a Posix extended regular expression *) val compile : Core.t -> Core.re (** Regular expression compilation *) val compile_pat : ?opts:(opt list) -> string -> Core.re (** [compile r] is defined as [Core.compile (Core.longest r)] *) (* Deviation from the standard / ambiguities in the standard --------------------------------------------------------- We tested the behavior of the Linux library (glibc) and the Solaris library. (1) An expression [efg] should be parsed as [(ef)g]. All implementations parse it as [e(fg)]. (2) When matching the pattern "((a)|b)*" against the string "ab", the sub-expression "((a)|b)" should match "b", and the sub-expression "(a)" should not match anything. In both implementation, the sub-expression "(a)" matches "a". (3) When matching the pattern "(aa?)*" against the string "aaa", it is not clear whether the final match of the sub-expression "(aa?)" is the last "a" (all matches of the sub-expression are successively maximized), or "aa" (the final match is maximized). Both implementations implements the first case. (4) When matching the pattern "((a?)|b)*" against the string "ab", the sub-expression "((a?)|b)" should match the empty string at the end of the string (it is better to match the empty string than to match nothing). In both implementations, this sub-expression matches "b". (Strangely, in the Linux implementation, the sub-expression "(a?)" correctly matches the empty string at the end of the string) This library behaves the same way as the other libraries for all points, except for (2) and (4) where it follows the standard. The behavior of this library in theses four cases may change in future releases. *) ocaml-re-1.9.0/lib/re.ml000066400000000000000000000002021345204770300147250ustar00rootroot00000000000000include Core module Emacs = Emacs module Glob = Glob module Perl = Perl module Pcre = Pcre module Posix = Posix module Str = Str ocaml-re-1.9.0/lib/str.ml000066400000000000000000000202621345204770300151370ustar00rootroot00000000000000(***********************************************************************) (* *) (* Objective Caml *) (* *) (* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) (* *) (* Copyright 1996 Institut National de Recherche en Informatique et *) (* en Automatique. All rights reserved. This file is distributed *) (* under the terms of the GNU Library General Public License, with *) (* linking exception. *) (* *) (***********************************************************************) (* Modified by Jerome.Vouillon@pps.jussieu.fr for integration in RE *) (* $Id: re_str.ml,v 1.3 2002/07/03 15:47:54 vouillon Exp $ *) module Re = Core type regexp = { re: Re.t ; mtch: Re.re Lazy.t ; srch: Re.re Lazy.t } let compile_regexp s c = let re = Emacs.re ~case:(not c) s in { re ; mtch = lazy (Re.compile (Re.seq [Re.start; re])) ; srch = lazy (Re.compile re) } let state = ref None let string_match re s p = try state := Some (Re.exec ~pos:p (Lazy.force re.mtch) s); true with Not_found -> state := None; false let string_partial_match re s p = match Re.exec_partial ~pos:p (Lazy.force re.mtch) s with `Full -> string_match re s p | `Partial -> true | `Mismatch -> false let search_forward re s p = try let res = Re.exec ~pos:p (Lazy.force re.srch) s in state := Some res; fst (Re.Group.offset res 0) with Not_found -> state := None; raise Not_found let rec search_backward re s p = try let res = Re.exec ~pos:p (Lazy.force re.mtch) s in state := Some res; p with Not_found -> state := None; if p = 0 then raise Not_found else search_backward re s (p - 1) let valid_group n = n >= 0 && n < 10 && ( match !state with | None -> false | Some m -> n < Re.Group.nb_groups m ) let offset_group i = match !state with | Some m -> Re.Group.offset m i | None -> raise Not_found let group_len i = try let (b, e) = offset_group i in e - b with Not_found -> 0 let rec repl_length repl p q len = if p < len then begin if repl.[p] <> '\\' then repl_length repl (p + 1) (q + 1) len else begin let p = p + 1 in if p = len then failwith "Str.replace: illegal backslash sequence"; let q = match repl.[p] with | '\\' -> q + 1 | '0' .. '9' as c -> q + group_len (Char.code c - Char.code '0') | _ -> q + 2 in repl_length repl (p + 1) q len end end else q let rec replace orig repl p res q len = if p < len then begin let c = repl.[p] in if c <> '\\' then begin Bytes.set res q c; replace orig repl (p + 1) res (q + 1) len end else begin match repl.[p + 1] with '\\' -> Bytes.set res q '\\'; replace orig repl (p + 2) res (q + 1) len | '0' .. '9' as c -> let d = try let (b, e) = offset_group (Char.code c - Char.code '0') in let d = e - b in if d > 0 then String.blit orig b res q d; d with Not_found -> 0 in replace orig repl (p + 2) res (q + d) len | c -> Bytes.set res q '\\'; Bytes.set res (q + 1) c; replace orig repl (p + 2) res (q + 2) len end end let replacement_text repl orig = let len = String.length repl in let res = Bytes.create (repl_length repl 0 0 len) in replace orig repl 0 res 0 (String.length repl); Bytes.unsafe_to_string res let quote s = let len = String.length s in let buf = Buffer.create (2 * len) in for i = 0 to len - 1 do match s.[i] with '[' | ']' | '*' | '.' | '\\' | '?' | '+' | '^' | '$' as c -> Buffer.add_char buf '\\'; Buffer.add_char buf c | c -> Buffer.add_char buf c done; Buffer.contents buf let string_before s n = String.sub s 0 n let string_after s n = String.sub s n (String.length s - n) let first_chars s n = String.sub s 0 n let last_chars s n = String.sub s (String.length s - n) n let regexp e = compile_regexp e false let regexp_case_fold e = compile_regexp e true let regexp_string s = compile_regexp (quote s) false let regexp_string_case_fold s = compile_regexp (quote s) true let group_beginning n = if not (valid_group n) then invalid_arg "Str.group_beginning"; let pos = fst (offset_group n) in if pos = -1 then raise Not_found else pos let group_end n = if not (valid_group n) then invalid_arg "Str.group_end"; let pos = snd (offset_group n) in if pos = -1 then raise Not_found else pos let matched_group n txt = let (b, e) = offset_group n in String.sub txt b (e - b) let replace_matched repl matched = replacement_text repl matched let match_beginning () = group_beginning 0 and match_end () = group_end 0 and matched_string txt = matched_group 0 txt let substitute_first expr repl_fun text = try let pos = search_forward expr text 0 in String.concat "" [string_before text pos; repl_fun text; string_after text (match_end ())] with Not_found -> text 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 String.concat "" (List.rev (replace [] 0 false)) let global_replace expr repl text = global_substitute expr (replacement_text repl) text and replace_first expr repl text = substitute_first expr (replacement_text repl) text let search_forward_progress re s p = let pos = search_forward re s p in if match_end () > p then pos else if p < String.length s then search_forward re s (p + 1) else raise Not_found let bounded_split expr text num = let start = if string_match expr text 0 then match_end () else 0 in let rec split accu start n = if start >= String.length text then accu else if n = 1 then (string_after text start) :: accu else try let pos = search_forward_progress expr text start in split ((String.sub text start (pos-start)) :: accu) (match_end ()) (n - 1) with Not_found -> (string_after text start) :: accu in List.rev (split [] start num) let split expr text = bounded_split expr text 0 let bounded_split_delim expr text num = let rec split accu start n = if start > String.length text then accu else if n = 1 then (string_after text start) :: accu else try let pos = search_forward_progress expr text start in split (String.sub text start (pos-start) :: accu) (match_end ()) (n - 1) with Not_found -> (string_after text start) :: accu in if text = "" then [] else List.rev (split [] 0 num) let split_delim expr text = bounded_split_delim expr text 0 type split_result = Text of string | Delim of string let bounded_full_split expr text num = let rec split accu start n = if start >= String.length text then accu else if n = 1 then Text (string_after text start) :: accu else try let pos = search_forward_progress expr text start in let s = matched_string text in if pos > start then split (Delim (s) :: Text (String.sub text start (pos - start)) :: accu) (match_end ()) (n - 1) else split (Delim (s) :: accu) (match_end ()) (n - 1) with Not_found -> Text (string_after text start) :: accu in List.rev (split [] 0 num) let full_split expr text = bounded_full_split expr text 0 ocaml-re-1.9.0/lib/str.mli000066400000000000000000000231151345204770300153100ustar00rootroot00000000000000(***********************************************************************) (* *) (* Objective Caml *) (* *) (* Xavier Leroy, projet Cristal, INRIA Rocquencourt *) (* *) (* Copyright 1996 Institut National de Recherche en Informatique et *) (* en Automatique. All rights reserved. This file is distributed *) (* under the terms of the GNU Library General Public License, with *) (* linking exception. *) (* *) (***********************************************************************) (* $Id: re_str.mli,v 1.1 2002/01/16 14:16:04 vouillon Exp $ *) (** Module [Str]: regular expressions and high-level string processing *) (** {2 Regular expressions} *) type regexp (** The type of compiled regular expressions. *) val regexp: string -> regexp (** Compile a regular expression. The syntax for regular expressions is the same as in Gnu Emacs. The special characters are [$^.*+?[]]. The following constructs are recognized: - [. ] matches any character except newline - [* ] (postfix) matches the previous expression zero, one or several times - [+ ] (postfix) matches the previous expression one or several times - [? ] (postfix) matches the previous expression once or not at all - [[..] ] character set; ranges are denoted with [-], as in [[a-z]]; an initial [^], as in [[^0-9]], complements the set - [^ ] matches at beginning of line - [$ ] matches at end of line - [\| ] (infix) alternative between two expressions - [\(..\)] grouping and naming of the enclosed expression - [\1 ] the text matched by the first [\(...\)] expression ([\2] for the second expression, etc) - [\b ] matches word boundaries - [\ ] quotes special characters. *) val regexp_case_fold: string -> regexp (** Same as [regexp], but the compiled expression will match text in a case-insensitive way: uppercase and lowercase letters will be considered equivalent. *) val quote: string -> string (** [Str.quote s] returns a regexp string that matches exactly [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 matches in a case-insensitive way. *) (** {2 String matching and searching} *) val string_match: regexp -> string -> int -> bool (** [string_match r s start] tests whether the characters in [s] starting at position [start] match the regular expression [r]. The first character of a string has position [0], as usual. *) val search_forward: regexp -> string -> int -> int (** [search_forward r s start] searches the string [s] for a substring matching the regular expression [r]. The search starts at position [start] and proceeds towards the end of the string. Return the position of the first character of the matched substring, or raise [Not_found] if no substring matches. *) val search_backward: regexp -> string -> int -> int (** Same as [search_forward], but the search proceeds towards the beginning of the string. *) val string_partial_match: regexp -> string -> int -> bool (** Similar to [string_match], but succeeds whenever the argument string is a prefix of a string that matches. This includes the case of a true complete match. *) val matched_string: string -> string (** [matched_string s] returns the substring of [s] that was matched by the latest [string_match], [search_forward] or [search_backward]. The user must make sure that the parameter [s] is the same string 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. *) val matched_group: int -> string -> string (** [matched_group n s] returns the substring of [s] that was matched by the [n]th group [\(...\)] of the regular expression during the latest [string_match], [search_forward] or [search_backward]. The user must make sure that the parameter [s] is the same string that was passed to the matching or searching function. [matched_group n s] raises [Not_found] if the [n]th group of the regular expression was not matched. This can happen with groups inside alternatives [\|], options [?] or repetitions [*]. For instance, the empty string will match [\(a\)*], but [matched_group 1 ""] will raise [Not_found] 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. *) (** {2 Replacement} *) val global_replace: regexp -> string -> string -> string (** [global_replace regexp templ s] returns a string identical to [s], except that all substrings of [s] that match [regexp] have been replaced by [templ]. The replacement template [templ] can contain [\1], [\2], etc; these sequences will be replaced by the text matched by the corresponding group in the regular expression. [\0] stands for the text matched by the whole regular expression. *) val replace_first: regexp -> string -> string -> string (** Same as [global_replace], except that only the first substring matching the regular expression is replaced. *) val global_substitute: regexp -> (string -> string) -> string -> string (** [global_substitute regexp subst s] returns a string identical to [s], except that all substrings of [s] that match [regexp] have been replaced by the result of function [subst]. The function [subst] is called once for each matching substring, and receives [s] (the whole text) as argument. *) val substitute_first: regexp -> (string -> string) -> string -> string (** Same as [global_substitute], except that only the first substring matching the regular expression is replaced. *) val replace_matched : string -> string -> string (** [replace_matched repl s] returns the replacement text [repl] in which [\1], [\2], etc. have been replaced by the text matched by the corresponding groups in the most recent matching operation. [s] must be the same string that was matched during this matching operation. *) (** {2 Splitting} *) val split: regexp -> string -> string list (** [split r s] splits [s] into substrings, taking as delimiters the substrings that match [r], and returns the list of substrings. For instance, [split (regexp "[ \t]+") s] splits [s] into blank-separated words. An occurrence of the delimiter at the beginning and at the end of the string is ignored. *) val bounded_split: regexp -> string -> int -> string list (** Same as [split], but splits into at most [n] substrings, where [n] is the extra integer parameter. *) val split_delim: regexp -> string -> string list 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"]]. *) type split_result = Text of string | Delim of string val full_split: regexp -> string -> split_result list 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 [[Delim "{"; Text "ab"; Delim "}"]]. *) (** {2 Extracting substrings} *) val string_before: string -> int -> string (** [string_before s n] returns the substring of all characters of [s] that precede position [n] (excluding the character at position [n]). *) val string_after: string -> int -> string (** [string_after s n] returns the substring of all characters of [s] that follow position [n] (including the character at position [n]). *) val first_chars: string -> int -> string (** [first_chars s n] returns the first [n] characters of [s]. This is the same function as [string_before]. *) val last_chars: string -> int -> string (** [last_chars s n] returns the last [n] characters of [s]. *) ocaml-re-1.9.0/lib_test/000077500000000000000000000000001345204770300150325ustar00rootroot00000000000000ocaml-re-1.9.0/lib_test/.cvsignore000066400000000000000000000001111345204770300170230ustar00rootroot00000000000000*.cmi *.cmx re_match pcre_match re_scan pcre_scan unison unison2 unison3 ocaml-re-1.9.0/lib_test/dune000066400000000000000000000003211345204770300157040ustar00rootroot00000000000000(tests (libraries re fort_unit) (modules :standard \ test_str) (names test_easy test_re test_perl test_emacs test_glob test_pcre)) (test (libraries re fort_unit str) (modules test_str) (name test_str)) ocaml-re-1.9.0/lib_test/fort_unit/000077500000000000000000000000001345204770300170435ustar00rootroot00000000000000ocaml-re-1.9.0/lib_test/fort_unit/dune000066400000000000000000000001631345204770300177210ustar00rootroot00000000000000(rule (copy %{project_root}/lib/fmt.ml fmt.ml)) (library (name fort_unit) (wrapped false) (libraries re oUnit))ocaml-re-1.9.0/lib_test/fort_unit/fort_unit.ml000066400000000000000000000037161345204770300214150ustar00rootroot00000000000000(* ounit compatibility layer for fort tests *) open OUnit2 type ('a, 'b) either = | Left of 'a | Right of 'b let str_of_either f g = function | Left a -> f a | Right b -> g b let try_with f = try Right (f ()) with exn -> Left exn let expect_equal_app ?printer ?msg f x g y = let fx = try_with (fun () -> f x) in let gy = try_with (fun () -> g y) in let printer = let right x = match printer with | None -> "" | Some p -> p x in str_of_either Printexc.to_string right in assert_equal ~printer ?msg fx gy let collected_tests = ref [] let id x = x let not_found () = raise Not_found let bool_printer i = Printf.sprintf "%b" i let int_printer i = Printf.sprintf "%d" i let str_printer s = "\"" ^ String.escaped s ^ "\"" let ofs_printer (i0,i1) = Printf.sprintf "(%d,%d)" i0 i1 let list_printer f l = "[" ^ (String.concat "; " (List.map f l)) ^ "]" let arr_printer f a = "[|" ^ (String.concat "; " (List.map f (Array.to_list a))) ^ "|]" let opt_printer f = function | None -> "" | Some s -> "Some (" ^ (f s) ^ ")" let arr_str_printer = arr_printer str_printer let arr_ofs_printer = arr_printer ofs_printer let list_ofs_printer = list_printer ofs_printer let fail = assert_failure let expect_eq_bool ?msg f x g y = 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_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 = expect_equal_app ?msg ~printer:arr_str_printer f x g y let expect_eq_arr_ofs ?msg f x g y = expect_equal_app ?msg ~printer:arr_ofs_printer f x g y let expect_eq_list_str ?msg f x g y = expect_equal_app ?msg ~printer:(list_printer str_printer) f x g y let expect_pass name run = collected_tests := (name >:: (fun _ -> run ())) :: !collected_tests let run_test_suite suite_name = run_test_tt_main (suite_name >::: !collected_tests) ocaml-re-1.9.0/lib_test/old/000077500000000000000000000000001345204770300156105ustar00rootroot00000000000000ocaml-re-1.9.0/lib_test/old/Input000066400000000000000000000010671345204770300166360ustar00rootroot00000000000000datafile for regex matching of phone numbers test the following numbers should match: (111) 111 1111 111 222-2222 (111) 333-3333 111 444 4444 foo (111) 555 5555 foo 111 666-6666 foo (111) 777-7777 foo 111 888 8888 foo (111) 999 9999 bar foo 111 000-0000 bar foo (111) 232-1111 bar foo 111 242 1111 bar The following should fail to match: 2(212) 222 2222 2232 222-2222 (242) 222-22222 2252 222 2222 foo (262) 2222222 foo 272 2222222 foo (282) 222-22227 foo 292 222 22222 foo (202).222 2222 bar foo 211@22222222 bar foo (213 222-2222 bar foo 214) 222 2222 bar ocaml-re-1.9.0/lib_test/old/glob.ml000066400000000000000000000020271345204770300170660ustar00rootroot00000000000000(** This is a little command line tool to test the library. @author Christian Lindig *) module R = Re module G = Re.Glob exception Error of string let error fmt = Printf.kprintf (fun msg -> raise (Error msg)) fmt let eprintf = Printf.eprintf let printf = Printf.printf let (@@) f x = f x let glob pattern str = let rx = R.compile @@ R.whole_string @@ G.glob ~expand_braces:true pattern in (* let () = R.print_re Format.std_formatter rx in *) if R.execp rx str then printf "%s matches: %s\n" pattern str else printf "%s doesn't match: %s\n" pattern str let main () = let argv = Array.to_list Sys.argv in let this = List.hd argv in let args = List.tl argv in match args with | [] | [_] -> error "usage: %s pattern string .." this | p :: strs -> List.iter (glob p) strs let () = try main (); exit 0 with | Error(msg) -> eprintf "Error: %s\n" msg; exit 1 | _ -> eprintf "unknown exception raised\n"; exit 1 ocaml-re-1.9.0/lib_test/old/longest.c000066400000000000000000000022031345204770300174240ustar00rootroot00000000000000 #include #include main () { regex_t preg; regmatch_t pmatch[3]; regcomp (&preg, "(aa?)*", REG_EXTENDED); regexec (&preg, "aaa", 2, pmatch, 0); printf ("%d %d %d %d (expected: 0 3 1 3)\n", pmatch[0].rm_so, pmatch[0].rm_eo, pmatch[1].rm_so, pmatch[1].rm_eo); regcomp (&preg, "(a*)(ab)?b*", REG_EXTENDED); regexec (&preg, "aaabb", 3, pmatch, 0); printf ("%d %d %d %d %d %d (expected: 0 5 0 2 2 4)\n", pmatch[0].rm_so, pmatch[0].rm_eo, pmatch[1].rm_so, pmatch[1].rm_eo, pmatch[2].rm_so, pmatch[2].rm_eo); regcomp (&preg, "((a?)|b)*", REG_EXTENDED); regexec (&preg, "ab", 3, pmatch, 0); printf ("%d %d %d %d %d %d (expected: 0 2 1 2 -1 -1)\n", pmatch[0].rm_so, pmatch[0].rm_eo, pmatch[1].rm_so, pmatch[1].rm_eo, pmatch[2].rm_so, pmatch[2].rm_eo); regcomp (&preg, "((a)|b)*", REG_EXTENDED); regexec (&preg, "ab", 3, pmatch, 0); printf ("%d %d %d %d %d %d (expected: 0 2 1 2 -1 -1)\n", pmatch[0].rm_so, pmatch[0].rm_eo, pmatch[1].rm_so, pmatch[1].rm_eo, pmatch[2].rm_so, pmatch[2].rm_eo); } ocaml-re-1.9.0/lib_test/old/pcre_match.ml000066400000000000000000000027001345204770300202460ustar00rootroot00000000000000(* * $Id: pcre_match.ml,v 1.1.1.1 2001/09/21 15:54:12 vouillon Exp $ * http://www.bagley.org/~doug/shootout/ * from: Markus Mottl *) open Re_pcre let rex = regexp ~flags:[`EXTENDED] "(?: ^ | [^\d\(]) # must be preceeded by non-digit (\(\d\d\d\)|\d\d\d) # match 1: area code [ ] # area code followed by one space \d\d\d # prefix of 3 digits [ -] # separator is either space or dash \d\d\d\d # last 4 digits (?: \D|$) # must be followed by a non-digit (or EOL)" let phones = let lines = ref [] in foreach_line (fun line -> lines := line :: !lines); List.rev !lines let check_phone irflags ar cnt must_print line = try unsafe_pcre_exec irflags rex 0 line 4 ar; let num = String.copy "(...) ...-...." and pos = Array.unsafe_get ar 2 in let ofs = if String.unsafe_get line pos = '(' then 1 else 0 in let pos = pos + ofs in String.unsafe_blit line pos num 1 3; let pos = pos + ofs + 4 in String.unsafe_blit line pos num 6 3; String.unsafe_blit line (pos + 4) num 10 4; if must_print then Printf.printf "%d: %s\n" !cnt num; incr cnt with Not_found -> () let n = if Array.length Sys.argv > 1 then int_of_string Sys.argv.(1) else 1;; for i = 2 to n do List.iter (check_phone (rflags []) (Array.create 6 0) (ref 1) false) phones done; List.iter (check_phone (rflags []) (Array.create 6 0) (ref 1) true) phones ocaml-re-1.9.0/lib_test/old/pcre_scan.ml000077500000000000000000000002521345204770300201010ustar00rootroot00000000000000 let x = Re_pcre.regexp "aa?b" let _ = let s = String.make (1024*1024) 'a' in s.[1024*1024-1] <- 'b'; for _i = 0 to 99 do ignore (Re_pcre.exec ~rex:x s) done ocaml-re-1.9.0/lib_test/old/perl_scan.pl000066400000000000000000000001441345204770300201120ustar00rootroot00000000000000$s = 'a' x (1024 * 1024 - 1) . 'b'; for ($i = 1; $i < 100; $i++) { print "$&\n" if $s =~ /aa?b/ ; } ocaml-re-1.9.0/lib_test/old/re_match.ml000066400000000000000000000033141345204770300177250ustar00rootroot00000000000000(* * $Id: re_match.ml,v 1.2 2001/10/03 15:04:59 vouillon Exp $ * http://www.bagley.org/~doug/shootout/ * from: Markus Mottl *) let rex = let three_digits = Re.seq [Re.digit; Re.digit; Re.digit] in Re.compile (Re.seq [(* Must be preceeded by a non-digit *) Re.alt [Re.bol; Re.compl [Re.digit; Re.char '(']]; (* Area code *) Re.group (Re.alt [Re.seq [Re.char '('; three_digits; Re.char ')']; three_digits]); (* One space *) Re.char ' '; (* Prefix of 3 digits *) three_digits; (* Separator: either a space or a dash *) Re.set " -"; (* Last for digits *) three_digits; Re.digit; (* Must be followed by a non-digit (or EOL) *) Re.alt [Re.eol; Re.compl [Re.digit]]]) let foreach_line ?(ic = stdin) f = try while true do f (input_line ic) done with End_of_file -> () let phones = let lines = ref [] in let ic = open_in "Input" in foreach_line ~ic (fun line -> lines := line :: !lines); close_in ic; List.rev !lines let check_phone cnt must_print line = try let matches = Re.exec rex line in let num = "(...) ...-...." in let (pos, _) = Re.Group.offset matches 1 in let ofs = if line.[pos] = '(' then 1 else 0 in let pos = pos + ofs in String.blit line pos num 1 3; let pos = pos + ofs + 4 in String.blit line pos num 6 3; String.blit line (pos + 4) num 10 4; if must_print then Printf.printf "%d: %s\n" !cnt num; incr cnt with Not_found -> () let n = if Array.length Sys.argv > 1 then int_of_string Sys.argv.(1) else 1;; for _i = 2 to n do List.iter (check_phone (ref 1) false) phones done; List.iter (check_phone (ref 1) true) phones ocaml-re-1.9.0/lib_test/old/re_scan.ml000066400000000000000000000003031345204770300175500ustar00rootroot00000000000000 open Re let x = compile (seq [char 'a'; opt (char 'a'); char 'b']) let _ = let s = String.make (1024*1024) 'a' in s.[1024*1024-1] <- 'b'; for _i = 0 to 99 do ignore (exec x s) done ocaml-re-1.9.0/lib_test/old/scan.ml000077500000000000000000000067731345204770300171060ustar00rootroot00000000000000type state = { idx : int; next : state array } type info = { i_cols : string; last : int } let unknown = {idx = -1; next = [||]} let st1 = { idx = 0; next = Array.make 256 unknown } let st2 = { idx = 0; next = Array.make 256 st1 } let cols = String.create 256 let _ = for i = 0 to 255 do st1.next.(i) <- st2; cols.[i] <- Char.chr i done (* 1.33 let rec loop s pos last st = if pos < last then begin ignore s.[pos]; loop s (pos + 1) last st.next.(127) end let exec s = loop s 0 (String.length s) st1 *) (* 1.67 let rec loop s pos last st = if pos < last then begin ignore s.[pos]; loop s (pos + 1) last st.next.(127) end let exec s = loop s 0 (String.length s) st1 *) (* 1.76 let rec loop s pos last st = if pos < last then begin let c = s.[pos] in let st' = st.next.(Char.code c) in loop s (pos + 1) last st' end let exec s = loop s 0 (String.length s) st1 *) (* 1.81 let rec loop cols s pos last st = if pos < last then begin let c' = cols.[Char.code s.[pos]] in let st' = st.next.(Char.code c') in loop cols s (pos + 1) last st' end let exec s = loop cols s 0 (String.length s) st1 *) (* 1.84 let rec loop info s pos last st = if pos < last then begin let c' = info.i_cols.[Char.code s.[pos]] in let st' = st.next.(Char.code c') in loop info s (pos + 1) last st' end let exec s = loop {i_cols = cols; last = String.length s} s 0 (String.length s) st1 *) (* 1.95 let rec loop info s pos last st = if pos < info.last then begin let c' = info.i_cols.[Char.code s.[pos]] in let st' = st.next.(Char.code c') in loop info s (pos + 1) last st' end let exec s = loop {i_cols = cols; last = String.length s} s 0 (String.length s) st1 *) (* 1.85 let rec loop info s pos cols st = if pos < info.last then begin let c' = cols.[Char.code s.[pos]] in let st' = st.next.(Char.code c') in loop info s (pos + 1) cols st' end let exec s = loop {i_cols = cols; last = String.length s} s 0 cols st1 *) let rec loop info s pos cols st = if pos < info.last then begin let c1 = cols.[Char.code s.[pos]] in let st1 = st.next.(Char.code c1) in let pos = pos + 1 in let c2 = cols.[Char.code s.[pos]] in let st2 = st1.next.(Char.code c2) in let pos = pos + 1 in let c3 = cols.[Char.code s.[pos]] in let st3 = st2.next.(Char.code c3) in let pos = pos + 1 in let c4 = cols.[Char.code s.[pos]] in let st4 = st3.next.(Char.code c4) in loop info s (pos + 1) cols st4 end let exec s = loop {i_cols = cols; last = String.length s} s 0 cols st1 (* 2.20 let rec loop info s pos last st idx = if idx >= 0 then begin if pos < last then begin let c' = info.i_cols.[Char.code s.[pos]] in let st' = st.next.(Char.code c') in let idx = st'.idx in loop info s (pos + 1) last st' idx end end else () let exec s = loop {i_cols = cols; last = String.length s} s 0 (String.length s) st1 0 *) (* let rec loop info s pos cols st st' = if pos < info.last then begin let c' = cols.[Char.code s.[pos]] in let idx = st.idx in if idx >= 0 then begin let st' = st.next.(Char.code c') in loop info s (pos + 1) cols st' st end else if idx = -1 then () else (* Unknown *) validate info s pos st' end and validate info s pos st' = validate info s pos st' let exec s = loop {i_cols = cols; last = String.length s} s 0 cols st1 st1 *) let _ = let s = String.make (1024*1024) 'a' in s.[1024*1024-1] <- 'b'; for _i = 0 to 99 do ignore (exec s) done ocaml-re-1.9.0/lib_test/old/test_exec_iter.ml000077500000000000000000000006571345204770300211630ustar00rootroot00000000000000#!/usr/bin/env ocaml #use "topfind";; #directory "_build/lib";; #load "re.cma";; #load "re_posix.cma";; let re = Re.compile (Re_posix.re "a*(ab)");; let s = "aaaaabaaa aaabaaabaaaabaa axbaaba";; let rec iter_gen f g = match g() with | None -> () | Some x -> f x; iter_gen f g ;; Re.Easy.iter_gen re s |> iter_gen (fun s -> let i,j = Re.get_ofs s 0 in Printf.printf "%s at %d,%d\n" (Re.get s 0) i j );; ocaml-re-1.9.0/lib_test/old/unison.ml000066400000000000000000000112301345204770300174520ustar00rootroot00000000000000let desc = [ `Path "lablgtk-1.00/config.make"; `Path "lablgtk-1.00/lablgtktop_t"; `Path "lablgtk-1.00/lablgtktop"; `Path "lablgtk-1.00/lablgtkrun"; `Path "lablgtk-1.00/lablgtk"; `Path "unison3/src/unison"; `Name "core"; `Path "lipe/caisse/val_parse.h"; `Path "lipe/caisse/val_parse.c"; `Path "lipe/caisse/val_lex.c"; `Path "lipe/caisse/caisse"; `Path "lipe/runtime"; `Path "lipe/demo"; `Path "unison2/doc/unison-manual.ps"; `Path "unison/doc/unison-mal.ps"; `Name "*.ppi"; `Path "unison2/src/unison"; `Path "Xduce/xduce/pref.ml"; `Path "Xduce/xduce/xduce{,.opt}"; `Path "unison/src/TAGS"; `Path "unison/src/unison"; `Name "*.old"; `Name "#*#"; `Name "*.cm{i,o,x,a,xa}"; `Name "*.vo"; `Name "*{~,.aux,.bbl,.blg,.log,.toc,.o,.a}"; `Name "gmon.out"; `Name "ocamlprof.dump"; `Name "CVS"; `Name ".*.prcs_aux"; `Path "icfp2000/tools/src2tex"; `Path "icfp2000/temp.dvi"; `Path "icfp2000/main.dvi"; `Path "icfp2000/whole.dvi"; `Path "icfp2000/regsub.ps"; `Path "Views/main.dvi"; `Path "lipe/perso/caisse"; `Name "obsolete"; `Path "misc/fingerprint/cksum/cksum"; `Path "misc/relay/relay"; `Path "Xduce/xduce.current/xduce.opt"; `Path "Xduce/xduce.current/pref.ml"; `Path "Xduce/xduce.new/pref.ml"; `Path "Xduce/xduce.new/xduce.opt"; `Path "profiler/profiler"; `Path "ocaml/boot/Saved"; `Path "ocaml/byterun/ocamlrun"; `Path "ocaml/config/Makefile"; `Path "ocaml/config/m.h"; `Path "ocaml/config/s.h"; `Path "ocaml/expunge"; `Path "ocaml/asmcomp/arch.ml"; `Path "ocaml/asmcomp/emit.ml"; `Path "ocaml/asmcomp/proc.ml"; `Path "ocaml/asmcomp/reload.ml"; `Path "ocaml/asmcomp/scheduling.ml"; `Path "ocaml/asmcomp/selection.ml"; `Path "ocaml/debugger/ocamldebug"; `Path "ocaml/lex/ocamllex"; `Path "ocaml/ocaml"; `Path "ocaml/ocamlc"; `Path "ocaml/ocamlopt"; `Path "ocaml/otherlibs/dynlink/extract_crc"; `Path "ocaml/otherlibs/labltk/browser/ocamlbrowser"; `Path "ocaml/otherlibs/labltk/compiler/tkcompiler"; `Path "ocaml/otherlibs/str/regex-0.12/config.status"; `Path "ocaml/stdlib/camlheader"; `Path "ocaml/tools/cvt_emit"; `Path "ocaml/boot/camlheader"; `Path "ocaml/boot/ocamlrun"; `Path "ocaml/boot/ocamlyacc"; `Path "ocaml/otherlibs/labltk/lib/.depend"; `Path "ocaml/otherlibs/labltk/lib/labltk"; `Path "ocaml/otherlibs/labltk/lib/labltktop"; `Path "ocaml/otherlibs/labltk/lib/tk.ml"; `Path "ocaml/tools/ocamlcp"; `Path "ocaml/tools/ocamldep"; `Path "ocaml/tools/ocamlmktop"; `Path "ocaml/tools/ocamlprof"; `Path "ocaml/utils/config.ml"; `Path "ocaml/yacc/ocamlyacc"; `Path "Xduce/interleave/tools/src2tex"; `Path "xml/parser"; `Path "ocaml/ocamlopt.opt"; `Path "ocaml/boot/ocamlc"; `Path "ocaml/boot/ocamllex"; `Path "ocaml/ocamlc.opt"; `Path "specs/tools/src2f"; `Path "specs/tools/src2tex" ] let paths = [ "These"; "Xduce"; "unison"; "unison2"; "unison3"; "tinkertype"; "lipe"; "icfp2000"; "Views"; "sync"; "misc"; "lablgtk-1.00"; "mydb"; "yacc"; "db-papers"; "submissions"; "xml"; "profiler"; "specs"; "ocaml"; "rx" ] let rec children p = let rec loop ch dir = try let file = Unix.readdir dir in let ch' = if file = "." || file = ".." then ch else file :: ch in loop ch' dir with End_of_file -> ch in let dir = Unix.opendir p in let result = loop [] dir in Unix.closedir dir; result let is_dir p = try (Unix.lstat p).Unix.st_kind = Unix.S_DIR with Unix.Unix_error _ -> false let prefix ="/home/jerome/" let count = ref 0 let hit = ref 0 let rec visit rx p = (*incr count; if !count > 0 then raise Exit;*) try incr count; ignore (Re.exec ~group:false rx p); (*Format.eprintf "-%s@." p*) with Not_found -> (*Format.eprintf "+%s@." p;*) let fp = prefix ^ p in incr hit; if is_dir fp then List.iter (fun n -> visit rx (p ^ "/" ^ n)) (children fp) let _ = for i = 0 to 9 do count := 0; hit := 0; let rx = Re.seq [ Re.bos; Re.alt (List.map (fun p -> match p with `Path s -> Re.Glob.globx s | `Name s -> Re.seq [Re.no_group (Re_posix.re "(.*/)?"); Re.Glob.globx s]) desc); Re.eos ] in let rx = Re.compile rx in begin try List.iter (fun p -> visit rx p) paths with Exit -> () end; Format.eprintf "%d/%d@." !hit !count; done ocaml-re-1.9.0/lib_test/old/unison2.ml000066400000000000000000000104511345204770300175400ustar00rootroot00000000000000let desc = [ `Path "lablgtk-1.00/config.make"; `Path "lablgtk-1.00/lablgtktop_t"; `Path "lablgtk-1.00/lablgtktop"; `Path "lablgtk-1.00/lablgtkrun"; `Path "lablgtk-1.00/lablgtk"; `Path "unison3/src/unison"; `Name "core"; `Path "lipe/caisse/val_parse.h"; `Path "lipe/caisse/val_parse.c"; `Path "lipe/caisse/val_lex.c"; `Path "lipe/caisse/caisse"; `Path "lipe/runtime"; `Path "lipe/demo"; `Path "unison2/doc/unison-manual.ps"; `Path "unison/doc/unison-mal.ps"; `Name "*.ppi"; `Path "unison2/src/unison"; `Path "Xduce/xduce/pref.ml"; `Path "Xduce/xduce/xduce{,.opt}"; `Path "unison/src/TAGS"; `Path "unison/src/unison"; `Name "*.old"; `Name "#*#"; `Name "*.cm{i,o,x,a,xa}"; `Name "*.vo"; `Name "*{~,.aux,.bbl,.blg,.log,.toc,.o,.a}"; `Name "gmon.out"; `Name "ocamlprof.dump"; `Name "CVS"; `Name ".*.prcs_aux"; `Path "icfp2000/tools/src2tex"; `Path "icfp2000/temp.dvi"; `Path "icfp2000/main.dvi"; `Path "icfp2000/whole.dvi"; `Path "icfp2000/regsub.ps"; `Path "Views/main.dvi"; `Path "lipe/perso/caisse"; `Name "obsolete"; `Path "misc/fingerprint/cksum/cksum"; `Path "misc/relay/relay"; `Path "Xduce/xduce.current/xduce.opt"; `Path "Xduce/xduce.current/pref.ml"; `Path "Xduce/xduce.new/pref.ml"; `Path "Xduce/xduce.new/xduce.opt"; `Path "profiler/profiler"; `Path "ocaml/boot/Saved"; `Path "ocaml/byterun/ocamlrun"; `Path "ocaml/config/Makefile"; `Path "ocaml/config/m.h"; `Path "ocaml/config/s.h"; `Path "ocaml/expunge"; `Path "ocaml/asmcomp/arch.ml"; `Path "ocaml/asmcomp/emit.ml"; `Path "ocaml/asmcomp/proc.ml"; `Path "ocaml/asmcomp/reload.ml"; `Path "ocaml/asmcomp/scheduling.ml"; `Path "ocaml/asmcomp/selection.ml"; `Path "ocaml/debugger/ocamldebug"; `Path "ocaml/lex/ocamllex"; `Path "ocaml/ocaml"; `Path "ocaml/ocamlc"; `Path "ocaml/ocamlopt"; `Path "ocaml/otherlibs/dynlink/extract_crc"; `Path "ocaml/otherlibs/labltk/browser/ocamlbrowser"; `Path "ocaml/otherlibs/labltk/compiler/tkcompiler"; `Path "ocaml/otherlibs/str/regex-0.12/config.status"; `Path "ocaml/stdlib/camlheader"; `Path "ocaml/tools/cvt_emit"; `Path "ocaml/boot/camlheader"; `Path "ocaml/boot/ocamlrun"; `Path "ocaml/boot/ocamlyacc"; `Path "ocaml/otherlibs/labltk/lib/.depend"; `Path "ocaml/otherlibs/labltk/lib/labltk"; `Path "ocaml/otherlibs/labltk/lib/labltktop"; `Path "ocaml/otherlibs/labltk/lib/tk.ml"; `Path "ocaml/tools/ocamlcp"; `Path "ocaml/tools/ocamldep"; `Path "ocaml/tools/ocamlmktop"; `Path "ocaml/tools/ocamlprof"; `Path "ocaml/utils/config.ml"; `Path "ocaml/yacc/ocamlyacc"; `Path "Xduce/interleave/tools/src2tex"; `Path "xml/parser"; `Path "ocaml/ocamlopt.opt"; `Path "ocaml/boot/ocamlc"; `Path "ocaml/boot/ocamllex"; `Path "ocaml/ocamlc.opt"; `Path "specs/tools/src2f"; `Path "specs/tools/src2tex" ] let paths = [ "These"; "Xduce"; "unison"; "unison2"; "unison3"; "tinkertype"; "lipe"; "icfp2000"; "Views"; "sync"; "misc"; "lablgtk-1.00"; "mydb"; "yacc"; "db-papers"; "submissions"; "xml"; "profiler"; "specs"; "ocaml"; "rx" ] let rec children p = let rec loop ch dir = try let file = Unix.readdir dir in let ch' = if file = "." || file = ".." then ch else file :: ch in loop ch' dir with End_of_file -> ch in let dir = Unix.opendir p in let result = loop [] dir in Unix.closedir dir; result let is_dir p = try (Unix.lstat p).Unix.st_kind = Unix.S_DIR with Unix.Unix_error _ -> false let prefix ="/home/jerome/" let rec visit rx p = if Rx.match_string rx p then ((*Format.eprintf "-%s@." p*)) else begin (*Format.eprintf "+%s@." p;*) let fp = prefix ^ p in if is_dir fp then List.iter (fun n -> visit rx (p ^ "/" ^ n)) (children fp) end let _ = let rx = Rx.alt (List.map (fun p -> match p with `Path s -> Rx.globx s | `Name s -> Rx.seq [Rx.rx "(.*/)?"; Rx.globx s]) desc); in List.iter (fun p -> visit rx p) paths ocaml-re-1.9.0/lib_test/old/unison3.ml000066400000000000000000000117431345204770300175460ustar00rootroot00000000000000let desc = [ `Path "lablgtk-1.00/config.make"; `Path "lablgtk-1.00/lablgtktop_t"; `Path "lablgtk-1.00/lablgtktop"; `Path "lablgtk-1.00/lablgtkrun"; `Path "lablgtk-1.00/lablgtk"; `Path "unison3/src/unison"; `Name "core"; `Path "lipe/caisse/val_parse.h"; `Path "lipe/caisse/val_parse.c"; `Path "lipe/caisse/val_lex.c"; `Path "lipe/caisse/caisse"; `Path "lipe/runtime"; `Path "lipe/demo"; `Path "unison2/doc/unison-manual.ps"; `Path "unison/doc/unison-mal.ps"; `Name "*.ppi"; `Path "unison2/src/unison"; `Path "Xduce/xduce/pref.ml"; `Path "Xduce/xduce/xduce"; `Path "Xduce/xduce/xduce.opt"; `Path "unison/src/TAGS"; `Path "unison/src/unison"; `Name "*.old"; `Name "#*#"; `Name "*.cmi"; `Name "*.cmo"; `Name "*.cmx"; `Name "*.cma"; `Name "*.cmxa"; `Name "*.vo"; `Name "*~"; `Name "*.aux"; `Name "*.bbl"; `Name "*.blg"; `Name "*.log"; `Name "*.toc"; `Name "*.o"; `Name "*.a"; `Name "gmon.out"; `Name "ocamlprof.dump"; `Name "CVS"; `Name ".*.prcs_aux"; `Path "icfp2000/tools/src2tex"; `Path "icfp2000/temp.dvi"; `Path "icfp2000/main.dvi"; `Path "icfp2000/whole.dvi"; `Path "icfp2000/regsub.ps"; `Path "Views/main.dvi"; `Path "lipe/perso/caisse"; `Name "obsolete"; `Path "misc/fingerprint/cksum/cksum"; `Path "misc/relay/relay"; `Path "Xduce/xduce.current/xduce.opt"; `Path "Xduce/xduce.current/pref.ml"; `Path "Xduce/xduce.new/pref.ml"; `Path "Xduce/xduce.new/xduce.opt"; `Path "profiler/profiler"; `Path "ocaml/boot/Saved"; `Path "ocaml/byterun/ocamlrun"; `Path "ocaml/config/Makefile"; `Path "ocaml/config/m.h"; `Path "ocaml/config/s.h"; `Path "ocaml/expunge"; `Path "ocaml/asmcomp/arch.ml"; `Path "ocaml/asmcomp/emit.ml"; `Path "ocaml/asmcomp/proc.ml"; `Path "ocaml/asmcomp/reload.ml"; `Path "ocaml/asmcomp/scheduling.ml"; `Path "ocaml/asmcomp/selection.ml"; `Path "ocaml/debugger/ocamldebug"; `Path "ocaml/lex/ocamllex"; `Path "ocaml/ocaml"; `Path "ocaml/ocamlc"; `Path "ocaml/ocamlopt"; `Path "ocaml/otherlibs/dynlink/extract_crc"; `Path "ocaml/otherlibs/labltk/browser/ocamlbrowser"; `Path "ocaml/otherlibs/labltk/compiler/tkcompiler"; `Path "ocaml/otherlibs/str/regex-0.12/config.status"; `Path "ocaml/stdlib/camlheader"; `Path "ocaml/tools/cvt_emit"; `Path "ocaml/boot/camlheader"; `Path "ocaml/boot/ocamlrun"; `Path "ocaml/boot/ocamlyacc"; `Path "ocaml/otherlibs/labltk/lib/.depend"; `Path "ocaml/otherlibs/labltk/lib/labltk"; `Path "ocaml/otherlibs/labltk/lib/labltktop"; `Path "ocaml/otherlibs/labltk/lib/tk.ml"; `Path "ocaml/tools/ocamlcp"; `Path "ocaml/tools/ocamldep"; `Path "ocaml/tools/ocamlmktop"; `Path "ocaml/tools/ocamlprof"; `Path "ocaml/utils/config.ml"; `Path "ocaml/yacc/ocamlyacc"; `Path "Xduce/interleave/tools/src2tex"; `Path "xml/parser"; `Path "ocaml/ocamlopt.opt"; `Path "ocaml/boot/ocamlc"; `Path "ocaml/boot/ocamllex"; `Path "ocaml/ocamlc.opt"; `Path "specs/tools/src2f"; `Path "specs/tools/src2tex" ] let translate_char c = match c with '.' -> "\." | '*' -> "[^/]*" | _ -> String.make 1 c let translate_str s = let res = ref "" in for i = 0 to String.length s - 1 do res := !res ^ translate_char s.[i] done; !res let paths = [ "These"; "Xduce"; "unison"; "unison2"; "unison3"; "tinkertype"; "lipe"; "icfp2000"; "Views"; "sync"; "misc"; "lablgtk-1.00"; "mydb"; "yacc"; "db-papers"; "submissions"; "xml"; "profiler"; "specs"; "ocaml"; "rx" ] let rec children p = let rec loop ch dir = try let file = Unix.readdir dir in let ch' = if file = "." || file = ".." then ch else file :: ch in loop ch' dir with End_of_file -> ch in let dir = Unix.opendir p in let result = loop [] dir in Unix.closedir dir; result let is_dir p = try (Unix.lstat p).Unix.st_kind = Unix.S_DIR with Unix.Unix_error _ -> false let prefix ="/home/jerome/" let count = ref 0 let rec visit rx p = (*incr count; if !count > 50 then raise Exit;*) try ignore (Re_pcre.exec ~rex:rx p); (*Format.eprintf "-%s@." p*) with Not_found -> (*Format.eprintf "+%s@." p;*) let fp = prefix ^ p in if is_dir fp then List.iter (fun n -> visit rx (p ^ "/" ^ n)) (children fp) let _ = let l = List.map (fun p -> match p with `Path s -> translate_str s | `Name s -> "(?:.*/)?" ^ translate_str s) desc in let rx = "^(?:" ^ begin match l with x :: r -> x ^ List.fold_right (fun x rem -> "|" ^ x ^ rem) r "" | [] -> assert false end ^ ")$" in Format.eprintf "%s@." rx; for i = 0 to 9 do count := 0; let rx = Re_pcre.regexp rx in try List.iter (fun p -> visit rx p) paths with Exit -> () done ocaml-re-1.9.0/lib_test/test_easy.ml000066400000000000000000000073011345204770300173650ustar00rootroot00000000000000(* Tests for Re higher-level functions *) open OUnit module String = struct [@@@ocaml.warning "-32-3"] let capitalize_ascii = String.capitalize let uncapitalize_ascii = String.uncapitalize let uppercase_ascii = String.uppercase let lowercase_ascii = String.lowercase include String end let pp_str x = x let quote = Printf.sprintf "'%s'" let pp_list l = l |> List.map quote |> String.concat ", " |> Printf.sprintf "[ %s ]" let re_whitespace = Re.Posix.compile_pat "[\t ]+" let re_empty = Re.Posix.compile_pat "" let re_eol = Re.compile Re.eol let re_bow = Re.compile Re.bow let re_eow = Re.compile Re.eow let test_iter () = let re = Re.Posix.compile_pat "(ab)+" in assert_equal ~printer:pp_list ["abab"; "ab"; "ab"] (Re.matches re "aabab aaabba dab "); assert_equal ~printer:pp_list ["ab"; "abab"] (Re.matches ~pos:2 ~len:7 re "abab ababab"); assert_equal ~printer:pp_list [""; ""] (Re.matches re_empty "ab"); () let test_split () = assert_equal ~printer:pp_list ["aa"; "bb"; "c"; "d"] (Re.split re_whitespace "aa bb c d "); assert_equal ~printer:pp_list ["a"; "b"] (Re.split ~pos:1 ~len:4 re_whitespace "aa b c d"); assert_equal ~printer:pp_list ["a"; "full_word"; "bc"] (Re.split re_whitespace " a full_word bc "); assert_equal ~printer:pp_list ["a"; "b"; "c"; "d"] (Re.split re_empty "abcd"); assert_equal ~printer:pp_list ["a"; "\nb"] (Re.split re_eol "a\nb"); assert_equal ~printer:pp_list ["a "; "b"] (Re.split re_bow "a b"); assert_equal ~printer:pp_list ["a"; " b"] (Re.split re_eow "a b"); () let map_split_delim = List.map (function | `Text x -> `T x | `Delim s -> `D (Re.Group.get s 0) ) let pp_list' l = pp_list (List.map (function `T s -> s | `D s -> "delim '" ^ s ^ "'" ) l ) let test_split_full () = assert_equal ~printer:pp_list' [`T "aa"; `D " "; `T "bb"; `D " "; `T "c"; `D " "; `T "d"; `D " "] (Re.split_full re_whitespace "aa bb c d " |> map_split_delim); assert_equal ~printer:pp_list' [`T "a"; `D " \t"; `T "b"; `D " "] (Re.split_full ~pos:1 ~len:5 re_whitespace "aa \tb c d" |> map_split_delim); assert_equal ~printer:pp_list' [`D " "; `T "a"; `D " "; `T "full_word"; `D " "; `T "bc"; `D " "] (Re.split_full re_whitespace " a full_word bc " |> map_split_delim); assert_equal ~printer:pp_list' [`D ""; `T "a"; `D ""; `T "b"] (* XXX: not trivial *) (Re.split_full re_empty "ab" |> map_split_delim); () let test_replace () = let re = Re.Posix.compile_pat "[a-zA-Z]+" in let f sub = String.capitalize_ascii (Re.Group.get sub 0) in assert_equal ~printer:pp_str " Hello World; I Love Chips!" (Re.replace re ~f " hello world; I love chips!"); assert_equal ~printer:pp_str " Allo maman, bobo" (Re.replace ~all:false re ~f " allo maman, bobo"); () let test_replace_string () = let re = Re.Posix.compile_pat "_[a-zA-Z]+_" in assert_equal ~printer:pp_str "goodbye world" (Re.replace_string re ~by:"goodbye" "_hello_ world"); assert_equal ~printer:pp_str "The quick brown fox" (Re.replace_string ~all:false re ~by:"brown" "The quick _XXX_ fox"); () let test_bug_55 () = let re = Re.(compile bol) in let res = Re.replace_string re ~by:"z" "abc" in assert_equal ~printer:pp_str "zabc" res; let re = Re.(compile eow) in let res = Re.replace_string re ~by:"X" "one two three" in assert_equal ~printer:pp_str "oneX twoX threeX" res let suite = "easy" >::: [ "iter" >:: test_iter ; "split" >:: test_split ; "split_full" >:: test_split_full ; "replace" >:: test_replace ; "replace_string" >:: test_replace_string ; "test sub 0 length matches" >:: test_bug_55 ] let () = ignore (run_test_tt_main suite) ocaml-re-1.9.0/lib_test/test_emacs.ml000066400000000000000000000062071345204770300175200ustar00rootroot00000000000000open Re open Re.Emacs open Fort_unit let eq_re r s = expect_equal_app ~msg:s id r re s ;; (* * Tests based on description of emacs regular expressions given at * http://www.gnu.org/manual/elisp-manual-20-2.5/html_chapter/elisp_34.html *) let _ = expect_pass "ordinary characters" (fun () -> eq_re (char 'a') "a"; ); expect_pass "concatenation" (fun () -> eq_re (seq [char 'a'; char 'b']) "ab"; ); expect_pass "escaping special characters" (fun () -> eq_re (char '.') "\\."; eq_re (char '*') "\\*"; eq_re (char '+') "\\+"; eq_re (char '?') "\\?"; eq_re (char '[') "\\["; eq_re (char ']') "\\]"; eq_re (char '^') "\\^"; eq_re (char '$') "\\$"; eq_re (char '\\') "\\\\"; ); expect_pass "special characters" (fun () -> eq_re notnl "."; eq_re (rep (char 'a')) "a*"; eq_re (rep1 (char 'a')) "a+"; eq_re (opt (char 'a')) "a?"; eq_re (alt [char 'b'; char 'a']) "[ab]"; eq_re (rg 'a' 'z') "[a-z]"; eq_re (alt [char '.'; char '%'; char '$'; rg 'a' 'z']) "[a-z$%.]"; eq_re (alt [char 'a'; char ']']) "[]a]"; eq_re (alt [char ']'; char '-']) "[]-]"; eq_re (alt [char '^'; char 'a']) "[a^]"; eq_re (compl [rg 'a' 'z']) "[^a-z]"; eq_re (compl [char '$'; rg 'a' 'z']) "[^a-z$]"; eq_re bol "^"; eq_re eol "$"; ); expect_pass "historical compatibility (not supported)" (fun () -> expect_equal_app (fun () -> raise Parse_error) () re "*ab"; expect_equal_app (fun () -> raise Parse_error) () re "+ab"; expect_equal_app (fun () -> raise Parse_error) () re "?ab"; ); expect_pass "alternative" (fun () -> eq_re (alt [char 'a'; char 'b']) "a\\|b"; eq_re (alt [seq [char 'a'; char 'a']; seq [char 'b'; char 'b']]) "aa\\|bb"; ); expect_pass "grouping" (fun () -> eq_re (group (char 'a')) "\\(a\\)"; eq_re (seq [group (alt [char 'a'; char 'b']); char 'c']) "\\(a\\|b\\)c" ); expect_pass "backreferences" (fun () -> expect_equal_app (fun () -> raise Not_supported) () re "\\0" ); expect_pass "word-constituent" (fun () -> eq_re (alt [alnum; char '_']) "\\w"; eq_re (compl [alnum; char '_']) "\\W"; ); (* syntax codes... ? *) expect_pass "contexts" (fun () -> eq_re bos "\\`"; eq_re eos "\\'"; eq_re start "\\="; eq_re (alt [bow; eow]) "\\b"; eq_re not_boundary "\\B"; eq_re bow "\\<"; eq_re eow "\\>"; ); run_test_suite "test_emacs" ocaml-re-1.9.0/lib_test/test_glob.ml000066400000000000000000000072311345204770300173510ustar00rootroot00000000000000open Re.Glob open Fort_unit let re_match ?pos ?len re s = Re.execp ?pos ?len (Re.compile re) s ;; let re_mismatch ?pos ?len re s = not (re_match ?pos ?len re s) let _ = assert (re_match (glob "foo*") "foobar" ); assert (re_mismatch (glob "fo?bar") "fobar" ); assert (re_match (glob "fo?bar") "foobar" ); assert (re_mismatch (glob "fo?bar") "foo0bar"); assert (re_match (glob "?oobar") "foobar" ); assert (re_match (glob "*bar") "foobar" ); assert (re_mismatch (glob "\\*bar") "foobar" ); assert (re_match (glob "\\*bar") "*bar" ); assert (re_match (glob "[ab]foo") "afoo" ); assert (re_match (glob "[ab]foo") "bfoo" ); assert (re_mismatch (glob "[ab]foo") "cfoo" ); assert (re_mismatch (glob "c[ab]foo") "cabfoo"); assert (re_match (glob ".foo" ) ".foo" ); assert (re_mismatch (glob ".foo" ) "afoo" ); assert (re_match (glob "*[.]foo") "a.foo" ); assert (re_match (glob "*[.]foo") "ba.foo"); assert (re_mismatch (glob "*.foo" ) ".foo" ); assert (re_mismatch (glob "*[.]foo") ".foo" ); assert (re_match (glob ~anchored:true "*/foo") "/foo"); assert (re_match (glob ~anchored:true "foo/*") "foo/"); assert (re_mismatch (glob "/[^f]") "/foo"); assert (re_match (glob "/[^f]") "/bar"); assert (re_mismatch (glob ~anchored:true "/[^f]") "/bar"); assert (re_mismatch (glob ~anchored:true "*") ".bar"); assert (re_match (glob "foo[.]bar") "foo.bar"); assert (re_mismatch (glob "[.]foo" ) ".foo" ); assert (re_mismatch (glob "foo[/]bar") "foo/bar"); assert (re_match (glob ~anchored:true "*bar") "foobar"); assert (re_match (glob "foo") "foobar"); assert (re_match (glob "bar") "foobar"); assert (re_mismatch (glob ~anchored:true "foo") "foobar"); assert (re_mismatch (glob ~anchored:true "bar") "foobar"); assert (re_mismatch (glob "{foo,bar}bar") "foobar" ); assert (re_match (glob "{foo,bar}bar") "{foo,bar}bar"); assert (re_mismatch (glob "foo?bar" ) "foo/bar" ); let pathname = true in let period = true in assert (re_mismatch (glob ~pathname ~period "?oobar") ".oobar"); assert (re_mismatch (glob ~pathname ~period "?oobar") "/oobar"); assert (re_mismatch (glob ~pathname ~period "f?obar") "f/obar"); assert (re_match (glob ~pathname ~period "f?obar") "f.obar"); assert (re_match (glob ~pathname ~period "f*.bar") "f.bar"); assert (re_match (glob ~pathname ~period "f?.bar") "fo.bar"); assert (re_match (glob ~pathname ~period "/.bar") "/.bar"); assert (re_mismatch (glob ~pathname ~period "*.bar") ".bar"); assert (re_mismatch (glob ~pathname ~period "?") "."); assert (re_mismatch (glob ~pathname ~period "/*bar") "/.bar"); assert (re_mismatch (glob "?oobar") ".oobar"); assert (re_mismatch (glob "?oobar") "/oobar"); let pathname = true in let period = false in assert (re_mismatch (glob ~pathname ~period "?oobar") "/oobar"); assert (re_match (glob ~pathname ~period "?oobar") ".oobar"); assert (re_mismatch (glob ~pathname ~period "f?obar") "f/obar"); assert (re_match (glob ~pathname ~period "f?obar") "f.obar"); let pathname = false in let period = false in assert (re_match (glob ~pathname ~period "?oobar") ".oobar"); assert (re_match (glob ~pathname ~period "?oobar") "/oobar"); assert (re_match (glob ~expand_braces:true "{foo,far}bar") "foobar" ); assert (re_match (glob ~expand_braces:true "{foo,far}bar") "farbar" ); assert (re_mismatch (glob ~expand_braces:true "{foo,far}bar") "{foo,far}bar"); run_test_suite "test_re"; ocaml-re-1.9.0/lib_test/test_pcre.ml000066400000000000000000000030171345204770300173550ustar00rootroot00000000000000open OUnit open Re.Pcre let sp = Printf.sprintf let string_of_group = function | Text s -> sp "Text %s" s | Delim s -> sp "Delim %s" s | Group (x, s) -> sp "Group (%d %s)" x s | NoGroup -> "NoGroup" let list_printer f xs = String.concat " ; " (List.map f xs) let test_blank_class _ = let re = Re.Perl.compile_pat "\\d[[:blank:]]\\d[[:blank:]]+[a-z]" in let successes = ["1 2 a"; "2\t3 z"; "9\t0 \t a"] in let failures = [""; "123"; " "; "1 3z"] in List.iter (fun s -> assert_bool ("String " ^ s ^ " should match") (Re.execp re s) ) successes; List.iter (fun s -> assert_bool ("String " ^ s ^ " should not match") (not (Re.execp re s)) ) failures let rex = regexp "[:_]" let split_empty _ = assert_equal (full_split ~rex "") [] let split_max_1 _ = assert_equal (full_split ~rex ~max:1 "xxx:yyy") [Text "xxx:yyy"] let rex = regexp "x(x)?" let printer = list_printer string_of_group let group_split1 _ = let sp = full_split ~rex "testxxyyy" in assert_equal ~printer sp [Text "test"; Delim "xx"; Group (1, "x"); Text "yyy"] let group_split2 _ = let sp = full_split ~rex "testxyyy" in assert_equal ~printer sp [Text "test"; Delim "x"; NoGroup; Text "yyy"] let test_fixtures = "test pcre features" >::: [ "test [:blank:] class" >:: test_blank_class ; "test splitting empty string" >:: split_empty ; "test split with max of 1" >:: split_max_1 ; "test group split 1" >:: group_split1 ; "test group split 2 - NoGroup" >:: group_split2] let _ = run_test_tt_main test_fixtures ocaml-re-1.9.0/lib_test/test_perl.ml000066400000000000000000000125411345204770300173700ustar00rootroot00000000000000open Re open Re.Perl open Fort_unit let eq_re ?opts r s = expect_equal_app ~msg:s id r (re ?opts) s ;; let parse_error_re ?opts s = try ignore (re ?opts s); OUnit2.assert_failure s with | Re.Perl.Parse_error -> () (* * Tests based on description of Perl regular expressions given at * http://www.perl.com/CPAN-local/doc/manual/html/pod/perlre.html *) let _ = expect_pass "ordinary characters" (fun () -> eq_re (char 'a') "a"; ); expect_pass "concatenation" (fun () -> eq_re (seq [char 'a'; char 'b']) "ab"; ); expect_pass "escaping metacharacters" (fun () -> eq_re (char '^') "\\^"; eq_re (char '.') "\\."; eq_re (char '$') "\\$"; eq_re (char '|') "\\|"; eq_re (char '(') "\\("; eq_re (char ')') "\\)"; eq_re (char '[') "\\["; eq_re (char ']') "\\]"; eq_re (char '*') "\\*"; eq_re (char '+') "\\+"; eq_re (char '?') "\\?"; eq_re (char '\\') "\\\\"; ); expect_pass "basic metacharacters" (fun () -> eq_re bos "^"; eq_re notnl "."; eq_re eos "$"; eq_re (alt [char 'a'; char 'b']) "a|b"; eq_re (alt [seq [char 'a'; char 'a']; seq [char 'b'; char 'b']]) "aa|bb"; eq_re (group (char 'a')) "(a)"; eq_re (seq [group (alt [char 'a'; char 'b']); char 'c']) "(a|b)c"; eq_re (alt [char 'b'; char 'a']) "[ab]"; eq_re (rg 'a' 'z') "[a-z]"; eq_re (alt [char '.'; char '%'; char '$'; rg 'a' 'z']) "[a-z$%.]"; eq_re (alt [char 'z'; char 'a'; char '-']) "[-az]"; eq_re (alt [char 'z'; char '-'; char 'a']) "[az-]"; eq_re (alt [char 'z'; char '-'; char 'a']) "[a\\-z]"; eq_re (alt [char 'a'; char ']']) "[]a]"; eq_re (alt [char ']'; char '-']) "[]-]"; eq_re (alt [char '^'; char 'a']) "[a^]"; eq_re (compl [rg 'a' 'z']) "[^a-z]"; eq_re (compl [char '$'; rg 'a' 'z']) "[^a-z$]"; eq_re (alt [char 'z'; char 'a'; char '-'; space]) "[a-\\sz]"; parse_error_re "[\\"; parse_error_re "[a-\\s"; ); expect_pass "greedy quantifiers" (fun () -> eq_re (greedy (rep (char 'a'))) "a*"; eq_re (greedy (rep1 (char 'a'))) "a+"; eq_re (greedy (opt (char 'a'))) "a?"; eq_re (greedy (repn (char 'a') 10 (Some 10))) "a{10}"; eq_re (greedy (repn (char 'a') 10 None)) "a{10,}"; eq_re (greedy (repn (char 'a') 10 (Some 12))) "a{10,12}"; ); expect_pass "non-greedy quantifiers" (fun () -> eq_re (non_greedy (rep (char 'a'))) "a*?"; eq_re (non_greedy (rep1 (char 'a'))) "a+?"; eq_re (non_greedy (opt (char 'a'))) "a??"; eq_re (non_greedy (repn (char 'a') 10 (Some 10))) "a{10}?"; eq_re (non_greedy (repn (char 'a') 10 None)) "a{10,}?"; eq_re (non_greedy (repn (char 'a') 10 (Some 12))) "a{10,12}?"; ); (* escape sequences (\t, etc) ? *) expect_pass "character sets" (fun () -> eq_re (alt [alnum; char '_']) "\\w"; eq_re (compl [alnum; char '_']) "\\W"; eq_re space "\\s"; eq_re (compl [space]) "\\S"; eq_re digit "\\d"; eq_re (compl [digit]) "\\D"; ); expect_pass "sets in classes" (fun () -> eq_re (alt [space; char 'a']) "[a\\s]"; ); expect_pass "zero-width assertions" (fun () -> eq_re (alt [bow; eow]) "\\b"; eq_re not_boundary "\\B"; eq_re bos "\\A"; eq_re leol "\\Z"; eq_re eos "\\z"; eq_re start "\\G"; ); expect_pass "backreferences" (fun () -> expect_equal_app (fun () -> raise Not_supported) () re "\\0" ); expect_pass "comments" (fun () -> eq_re (seq [char 'a'; epsilon; char 'b']) "a(?#comment)b"; parse_error_re "(?#"; ); expect_pass "clustering" (fun () -> (* modifier support ? *) eq_re (char 'a') "(?:a)"; eq_re (seq [alt [char 'a'; char 'b']; char 'c']) "(?:a|b)c"; ); (* lookahead assertions *) (* independent subexpression *) (* conditional expression *) (* pattern-match modifiers *) expect_pass "options" (fun () -> eq_re ~opts:[`Anchored] (seq [start; char 'a']) "a"; eq_re ~opts:[`Caseless] (no_case (char 'b')) "b"; eq_re ~opts:[`Dollar_endonly] leol "$"; eq_re ~opts:[`Dollar_endonly; `Multiline] eol "$"; eq_re ~opts:[`Dotall] any "."; (* Extended ? *) eq_re ~opts:[`Multiline] bol "^"; eq_re ~opts:[`Multiline] eol "$"; eq_re ~opts:[`Ungreedy] (non_greedy (rep (char 'a'))) "a*"; eq_re ~opts:[`Ungreedy] (greedy (rep (char 'a'))) "a*?"; ); run_test_suite "test_perl" ocaml-re-1.9.0/lib_test/test_re.ml000066400000000000000000000330741345204770300170400ustar00rootroot00000000000000module L = List open Re open OUnit2 open Fort_unit module List = L let re_match ?pos ?len r s res = expect_equal_app ~msg:(str_printer s) ~printer:arr_ofs_printer id res (fun () -> Group.all_offset (exec ?pos ?len (compile r) s)) () ;; let re_fail ?pos ?len r s = expect_equal_app ~msg:(str_printer s) ~printer:arr_ofs_printer not_found () (fun () -> Group.all_offset (exec ?pos ?len (compile r) s)) () ;; let correct_mark ?pos ?len r s il1 il2 = expect_equal_app ~msg:(str_printer s) ~printer:bool_printer id true (fun () -> let subs = exec ?pos ?len (compile r) s in List.for_all (Mark.test subs) il1 && List.for_all (fun x -> not (Mark.test subs x)) il2 ) () ;; (* Substring Extraction *) let _ = let r = seq [group (char 'a'); opt (group (char 'a')); group (char 'b')] in let m = exec (compile r) "ab" in expect_pass "Group.get" (fun () -> expect_eq_str id "ab" (Group.get m) 0; expect_eq_str id "a" (Group.get m) 1; expect_eq_str not_found () (Group.get m) 2; expect_eq_str id "b" (Group.get m) 3; expect_eq_str not_found () (Group.get 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; expect_eq_ofs not_found () (Group.offset m) 2; expect_eq_ofs id (1,2) (Group.offset m) 3; expect_eq_ofs not_found () (Group.offset m) 4; ); expect_pass "Group.all" (fun () -> expect_eq_arr_str id [|"ab";"a";"";"b"|] Group.all m ); expect_pass "Group.all_offset" (fun () -> expect_eq_arr_ofs id [|(0,2);(0,1);(-1,-1);(1,2)|] Group.all_offset m ); expect_pass "Group.test" (fun () -> expect_eq_bool id true (Group.test m) 0; expect_eq_bool id true (Group.test m) 1; expect_eq_bool id false (Group.test m) 2; expect_eq_bool id true (Group.test m) 3; expect_eq_bool id false (Group.test m) 4; ); (* Literal Match *) expect_pass "str" (fun () -> re_match (str "a") "a" [|(0,1)|]; re_fail (str "a") "b"; ); expect_pass "char" (fun () -> re_match (char 'a') "a" [|(0,1)|]; re_fail (char 'a') "b"; ); (* Basic Operations *) expect_pass "alt" (fun () -> re_match (alt [char 'a'; char 'b']) "a" [|(0,1)|]; re_match (alt [char 'a'; char 'b']) "b" [|(0,1)|]; re_fail (alt [char 'a'; char 'b']) "c"; ); expect_pass "seq" (fun () -> re_match (seq [char 'a'; char 'b']) "ab" [|(0,2)|]; re_fail (seq [char 'a'; char 'b']) "ac"; ); expect_pass "empty" (fun () -> re_fail (empty) ""; re_fail (empty) "a"; ); expect_pass "epsilon" (fun () -> re_match (epsilon) "" [|(0,0)|]; re_match (epsilon) "a" [|(0,0)|]; ); expect_pass "rep" (fun () -> re_match (rep (char 'a')) "" [|(0,0)|]; re_match (rep (char 'a')) "a" [|(0,1)|]; re_match (rep (char 'a')) "aa" [|(0,2)|]; re_match (rep (char 'a')) "b" [|(0,0)|]; ); expect_pass "rep1" (fun () -> re_match (rep1 (char 'a')) "a" [|(0,1)|]; re_match (rep1 (char 'a')) "aa" [|(0,2)|]; re_fail (rep1 (char 'a')) ""; re_fail (rep1 (char 'a')) "b"; ); expect_pass "repn" (fun () -> re_match (repn (char 'a') 0 None) "" [|(0,0)|]; re_match (repn (char 'a') 0 (Some 0)) "" [|(0,0)|]; re_match (repn (char 'a') 1 (Some 2)) "a" [|(0,1)|]; re_match (repn (char 'a') 1 (Some 2)) "aa" [|(0,2)|]; re_fail (repn (char 'a') 1 (Some 2)) ""; re_match (repn (char 'a') 1 (Some 2)) "aaa" [|(0,2)|]; expect_equal_app invalid_arg "Re.repn" (fun () -> repn empty (-1) None) (); expect_equal_app invalid_arg "Re.repn" (fun () -> repn empty 1 (Some 0)) (); ); expect_pass "opt" (fun () -> re_match (opt (char 'a')) "" [|(0,0)|]; re_match (opt (char 'a')) "a" [|(0,1)|]; ); (* String, line, word *) expect_pass "bol" (fun () -> re_match (seq [bol; char 'a']) "ab" [|(0,1)|]; re_match (seq [bol; char 'a']) "b\na" [|(2,3)|]; re_fail (seq [bol; char 'a']) "ba"; ); expect_pass "eol" (fun () -> re_match (seq [char 'a'; eol]) "ba" [|(1,2)|]; re_match (seq [char 'a'; eol]) "a\nb" [|(0,1)|]; re_match (seq [char 'a'; eol]) "ba\n" [|(1,2)|]; re_fail (seq [char 'a'; eol]) "ab"; ); expect_pass "bow" (fun () -> re_match (seq [bow; char 'a']) "a" [|(0,1)|]; re_match (seq [bow; char 'a']) "bb aa" [|(3,4)|]; re_fail (seq [bow; char 'a']) "ba ba"; ); expect_pass "eow" (fun () -> re_match (seq [char 'a'; eow]) "a" [|(0,1)|]; re_match (seq [char 'a'; eow]) "bb aa" [|(4,5)|]; re_fail (seq [char 'a'; eow]) "ab ab"; ); expect_pass "bos" (fun () -> re_match (seq [bos; char 'a']) "ab" [|(0,1)|]; re_fail (seq [bos; char 'a']) "b\na"; re_fail (seq [bos; char 'a']) "ba"; ); expect_pass "eos" (fun () -> re_match (seq [char 'a'; eos]) "ba" [|(1,2)|]; re_fail (seq [char 'a'; eos]) "a\nb"; re_fail (seq [char 'a'; eos]) "ba\n"; re_fail (seq [char 'a'; eos]) "ab"; ); expect_pass "leol" (fun () -> re_match (seq [char 'a'; leol]) "ba" [|(1,2)|]; re_fail (seq [char 'a'; leol]) "a\nb"; re_match (seq [char 'a'; leol]) "ba\n" [|(1,2)|]; re_fail (seq [char 'a'; leol]) "ab"; re_match (alt [str "b\n"; seq [char 'a'; leol]]) "ab\n" [|(1,3)|]; ); expect_pass "start" (fun () -> re_match ~pos:1 (seq [start; char 'a']) "xab" [|(1,2)|]; re_fail ~pos:1 (seq [start; char 'a']) "xb\na"; re_fail ~pos:1 (seq [start; char 'a']) "xba"; ); expect_pass "stop" (fun () -> re_match ~len:2 (seq [char 'a'; stop]) "bax" [|(1,2)|]; re_fail ~len:3 (seq [char 'a'; stop]) "a\nbx"; re_fail ~len:3 (seq [char 'a'; stop]) "ba\nx"; re_fail ~len:2 (seq [char 'a'; stop]) "abx"; ); expect_pass "word" (fun () -> re_match (word (str "aa")) "aa" [|(0,2)|]; re_match (word (str "aa")) "bb aa" [|(3,5)|]; re_fail (word (str "aa")) "aaa"; ); expect_pass "not_boundary" (fun () -> re_match (seq [not_boundary; char 'b'; not_boundary]) "abc" [|(1,2)|]; re_fail (seq [not_boundary; char 'a']) "abc"; re_fail (seq [char 'c'; not_boundary]) "abc"; ); (* Match semantics *) expect_pass "default match semantics" (fun () -> re_match (seq [(rep (alt [char 'a'; char 'b'])); char 'b']) "aabaab" [|(0,6)|]; re_match (alt [str "aa"; str "aaa"]) "aaaa" [|(0, 2)|]; re_match (alt [str "aaa"; str "aa"]) "aaaa" [|(0, 3)|]; ); expect_pass "shortest match" (fun () -> re_match (shortest (seq [(rep (alt [char 'a'; char 'b'])); char 'b'])) "aabaab" [|(0,3)|]; re_match (shortest (alt [str "aa"; str "aaa"])) "aaaa" [|(0, 2)|]; re_match (shortest (alt [str "aaa"; str "aa"])) "aaaa" [|(0, 2)|]; ); expect_pass "longest match" (fun () -> re_match (longest (seq [(rep (alt [char 'a'; char 'b'])); char 'b'])) "aabaab" [|(0,6)|]; re_match (longest (alt [str "aa"; str "aaa"])) "aaaa" [|(0, 3)|]; re_match (longest (alt [str "aaa"; str "aa"])) "aaaa" [|(0, 3)|]; ); expect_pass "first match" (fun () -> re_match (first (seq [(rep (alt [char 'a'; char 'b'])); char 'b'])) "aabaab" [|(0,6)|]; re_match (first (alt [str "aa"; str "aaa"])) "aaaa" [|(0, 2)|]; re_match (first (alt [str "aaa"; str "aa"])) "aaaa" [|(0, 3)|]; ); expect_pass "greedy" (fun () -> re_match (greedy (seq [(rep (alt [char 'a'; char 'b'])); char 'b'])) "aabaab" [|(0,6)|]; re_match (greedy (rep (group (opt (char 'a'))))) "aa" [|(0,2); (2,2)|]; ); expect_pass "non_greedy" (fun () -> re_match (non_greedy (longest (seq [(rep (alt [char 'a'; char 'b'])); char 'b']))) "aabaab" [|(0,6)|]; re_match (non_greedy (first (seq [(rep (alt [char 'a'; char 'b'])); char 'b']))) "aabaab" [|(0,3)|]; re_match (non_greedy (longest (rep (group (opt (char 'a')))))) "aa" [|(0,2); (1,2)|]; ); expect_pass "match semantics" (fun () -> let r = rep (group (alt [str "aaa"; str "aa"])) in re_match (longest r) "aaaaaaa" [|(0,7); (5, 7)|]; re_match (first r) "aaaaaaa" [|(0,6); (3, 6)|]; re_match (first (non_greedy r)) "aaaaaaa" [|(0,0); (-1, -1)|]; re_match (shortest r) "aaaaaaa" [|(0,0); (-1, -1)|]; let r' = rep (group (shortest (alt [str "aaa"; str "aa"]))) in re_match (longest r') "aaaaaaa" [|(0,7); (4, 7)|]; re_match (first r') "aaaaaaa" [|(0,6); (4, 6)|]; ); (* Group (or submatch) *) expect_pass "group" (fun () -> let r = seq [group (char 'a'); opt (group (char 'a')); group (char 'b')] in expect_eq_arr_ofs id [|(0,2);(0,1);(-1,-1);(1,2)|] (fun () -> Group.all_offset (exec (compile r) "ab")) () ); expect_pass "no_group" (fun () -> let r = no_group ( seq [group (char 'a'); opt (group (char 'a')); group (char 'b')] ) in expect_eq_arr_ofs id [|(0,2)|] (fun () -> Group.all_offset (exec (compile r) "ab")) () ); expect_pass "nest" (fun () -> let r = rep (nest (alt [group (char 'a'); char 'b'])) in re_match r "ab" [|(0,2); (-1, -1)|]; re_match r "ba" [|(0,2); (1, 2)|]; ); expect_pass "mark" (fun () -> let i, r = mark digit in correct_mark r "0" [i] []; ); expect_pass "mark seq" (fun () -> let i, r = mark digit in let r = seq [r; r] in correct_mark r "02" [i] [] ; ); expect_pass "mark rep" (fun () -> let i, r = mark digit in let r = rep r in correct_mark r "02" [i] []; ); expect_pass "mark alt" (fun () -> let ia, ra = mark (char 'a') in let ib, rb = mark (char 'b') in let r = alt [ra ; rb] in correct_mark r "a" [ia] [ib]; correct_mark r "b" [ib] [ia]; let r = rep r in correct_mark r "ab" [ia; ib] [] ; ); (* Character set *) expect_pass "set" (fun () -> re_match (rep1 (set "abcd")) "bcbadbabcdba" [|(0,12)|]; re_fail (set "abcd") "e"; ); expect_pass "rg" (fun () -> re_match (rep1 (rg '0' '9')) "0123456789" [|(0,10)|]; re_fail (rep1 (rg '0' '9')) "a"; ); expect_pass "inter" (fun () -> re_match (rep1 (inter [rg '0' '9'; rg '4' '6'])) "456" [|(0,3)|]; re_fail (rep1 (inter [rg '0' '9'; rg '4' '6'])) "7"; re_match (inter [alt [char 'a'; char 'b']; char 'b']) "b" [|(0,1)|]; ); expect_pass "diff" (fun () -> re_match (rep1 (diff (rg '0' '9') (rg '4' '6'))) "0123789" [|(0,7)|]; re_fail (rep1 (diff (rg '0' '9') (rg '4' '6'))) "4"; ); expect_pass "compl" (fun () -> re_match (rep1 (compl [rg '0' '9'; rg 'a' 'z'])) "A:Z+" [|(0,4)|]; re_fail (rep1 (compl [rg '0' '9'; rg 'a' 'z'])) "0"; re_fail (rep1 (compl [rg '0' '9'; rg 'a' 'z'])) "a"; ); (* Predefined character sets - should these be tested exhaustively? *) (* Case modifiers *) expect_pass "case" (fun () -> re_match (case (str "abc")) "abc" [|(0,3)|]; re_match (no_case (case (str "abc"))) "abc" [|(0,3)|]; re_fail (case (str "abc")) "ABC"; re_fail (no_case (case (str "abc"))) "ABC"; ); expect_pass "no_case" (fun () -> re_match (no_case (str "abc")) "abc" [|(0,3)|]; re_match (no_case (str "abc")) "ABC" [|(0,3)|]; re_match (case (no_case (str "abc"))) "abc" [|(0,3)|]; re_match (case (no_case (str "abc"))) "ABC" [|(0,3)|]; ); expect_pass "witness" (fun () -> let t r e = assert_equal ~printer:(fun x -> x) (witness r) e in t (set "ac") "a"; t (repn (str "foo") 3 None) "foofoofoo"; t (alt [char 'c' ; char 'd']) "c"; t (no_case (str "test")) "TEST"; t eol "" ); (* Fixed bugs *) expect_pass "bugs" (fun () -> try ignore (Re.compile (Re.Perl.re "(.*?)(\\WPl|\\Bpl)(.*)")) with _ -> fail "bug in Re.handle_case" ); let test msg re input expected = expect_pass msg (fun () -> expect_equal_app id expected id (exec_partial (compile re) input) ~printer:(function | `Partial -> "`Partial" | `Full -> "`Full" | `Mismatch -> "`Mismatch")) in test "exec_partial 1" (str "hello") "he" `Partial; test "exec_partial 2" (str "hello") "goodbye" `Partial; (* exec_partial 3 shoudl be `Full *) test "exec_partial 3" (str "hello") "hello" `Partial; test "exec_partial 4" (whole_string (str "hello")) "hello" `Partial; test "exec_partial 5" (whole_string (str "hello")) "goodbye" `Mismatch; test "exec_partial 6" (str "hello") "" `Partial; test "exec_partial 7" (str "") "hello" `Full; test "exec_partial 8" (whole_string (str "hello")) "" `Partial; run_test_suite "test_re" ocaml-re-1.9.0/lib_test/test_str.ml000066400000000000000000000161551345204770300172430ustar00rootroot00000000000000open Fort_unit open OUnit2 module type Str_intf = module type of Str module Test_matches (R : Str_intf) = struct let groups () = let group i = try `Found (R.group_beginning i) with | Not_found -> `Not_found | Invalid_argument _ -> `Not_exists in let rec loop acc i = match group i with | `Found p -> loop ((p, R.group_end i)::acc) (i + 1) | `Not_found -> loop ((-1, -1)::acc) (i + 1) | `Not_exists -> List.rev acc in loop [] 0 let eq_match ?(pos=0) ?(case=true) r s = let pat = if case then R.regexp r else R.regexp_case_fold r in try ignore (R.search_forward pat s pos); Some (groups ()) with Not_found -> None end module T_str = Test_matches(Str) module T_re = Test_matches(Re.Str) let eq_match ?pos ?case r s = expect_equal_app ~msg:(str_printer s) ~printer:(opt_printer (list_printer ofs_printer)) (fun () -> T_str.eq_match ?pos ?case r s) () (fun () -> T_re.eq_match ?pos ?case r s) () ;; let split_result_conv = List.map (function | Str.Delim x -> Re.Str.Delim x | Str.Text x -> Re.Str.Text x) let pp_split_result_list = Fmt.pp_olist (fun fmt x -> let (tag, arg) = match x with | Re.Str.Delim x -> ("Delim", x) | Re.Str.Text x -> ("Text", x) in Fmt.fprintf fmt "%s@ (\"%s\")" tag arg) let pp_fs pp_args pp_out fmt (name, re, args, ex, res) = let f fmt (mod_, r) = Fmt.fprintf fmt "%s.%s %a %a = %a" mod_ name Fmt.quote re pp_args args pp_out r in Fmt.fprintf fmt "@.%a@.%a" f ("Str", ex) f ("Re.Str", res) type ('a, 'b) test = { name: string ; pp_args : 'a Fmt.t ; pp_out : 'b Fmt.t ; re_str: Re.Str.regexp -> 'a -> 'b ; str: Str.regexp -> 'a -> 'b } let bounded_split_t = { name = "bounded_split" ; pp_args = (fun fmt (s, n) -> Fmt.fprintf fmt "%a %d" Fmt.quote s n) ; pp_out = Fmt.pp_str_list ; re_str = (fun re (s, n) -> Re.Str.bounded_split re s n) ; str = (fun re (s, n) -> Str.bounded_split re s n) } let bounded_full_split_t = { bounded_split_t with name = "bounded_full_split" ; pp_out = pp_split_result_list ; re_str = (fun re (s, n) -> Re.Str.bounded_full_split re s n) ; str = (fun re (s, n) -> split_result_conv (Str.bounded_full_split re s n)) } let full_split_t = { bounded_full_split_t with name = "full_split" ; pp_args = (fun fmt s -> Fmt.fprintf fmt "%a" Fmt.quote s) ; re_str = (fun re s -> Re.Str.full_split re s) ; str = (fun re s -> split_result_conv (Str.full_split re s)) } let split_delim_t = { full_split_t with name = "split_delim" ; pp_out = Fmt.pp_str_list ; re_str = (fun re s -> Re.Str.split_delim re s) ; str = (fun re s -> Str.split_delim re s) } let split_t = { name = "split" ; pp_out = Fmt.pp_str_list ; pp_args = full_split_t.pp_args ; re_str = (fun re s -> Re.Str.split re s) ; str = (fun re s -> Str.split re s) } let global_replace_t = { name = "global_replace" ; pp_out = Fmt.pp_print_string ; pp_args = (fun fmt (r, s) -> Fmt.fprintf fmt "%a %a" Fmt.quote r Fmt.quote s) ; re_str = (fun re (r, s) -> Re.Str.global_replace re r s) ; str = (fun re (r, s) -> Str.global_replace re r s) } let test t re args = assert_equal ~pp_diff:(fun fmt (ex, act) -> pp_fs t.pp_args t.pp_out fmt (t.name, re, args, ex, act)) ~printer:(Fmt.to_to_string t.pp_out) (t.re_str (Re.Str.regexp re) args) (t.str (Str.regexp re) args) let split_delim re s = test split_delim_t re s let split re s = test split_t re s let full_split re s = test full_split_t re s let bounded_split re s n = test bounded_split_t re (s, n) let bounded_full_split re s n = test bounded_full_split_t re (s, n) let global_replace re r s = test global_replace_t re (r, s) let _ = (* Literal Match *) expect_pass "str" (fun () -> eq_match "a" "a"; eq_match "a" "b"; ); (* Basic Operations *) expect_pass "alt" (fun () -> eq_match "a\\|b" "a"; eq_match "a\\|b" "b"; eq_match "a\\|b" "c"; ); expect_pass "seq" (fun () -> eq_match "ab" "ab"; eq_match "ab" "ac"; ); expect_pass "epsilon" (fun () -> eq_match "" ""; eq_match "" "a"; ); expect_pass "rep" (fun () -> eq_match "a*" ""; eq_match "a*" "a"; eq_match "a*" "aa"; eq_match "a*" "b"; ); expect_pass "rep1" (fun () -> eq_match "a+" "a"; eq_match "a+" "aa"; eq_match "a+" ""; eq_match "a+" "b"; ); expect_pass "opt" (fun () -> eq_match "a?" ""; eq_match "a?" "a"; ); (* String, line, word *) expect_pass "bol" (fun () -> eq_match "^a" "ab"; eq_match "^a" "b\na"; eq_match "^a" "ba"; ); expect_pass "eol" (fun () -> eq_match "a$" "ba"; eq_match "a$" "a\nb"; eq_match "a$" "ba\n"; eq_match "a$" "ab"; ); expect_pass "start" (fun () -> eq_match ~pos:1 "Za" "xab"; eq_match ~pos:1 "Za" "xb\na"; eq_match ~pos:1 "Za" "xba"; ); (* Match semantics *) expect_pass "match semantics" (fun () -> eq_match "\\(a\\|b\\)*b" "aabaab"; eq_match "aa\\|aaa" "aaaa"; eq_match "aaa\\|aa" "aaaa"; ); (* Group (or submatch) *) (* TODO: infinite loop *) expect_pass "group" (fun () -> eq_match "\\(a\\)\\(a\\)?\\(b\\)" "ab"; ); (* Character set *) expect_pass "rg" (fun () -> eq_match "[0-9]+" "0123456789"; eq_match "[0-9]+" "a"; ); expect_pass "compl" (fun () -> eq_match "[^0-9a-z]+" "A:Z+"; eq_match "[^0-9a-z]+" "0"; eq_match "[^0-9a-z]+" "a"; ); (* Case modifiers *) expect_pass "no_case" (fun () -> eq_match ~case:false "abc" "abc"; eq_match ~case:false "abc" "ABC"; ); expect_pass "global_replace" (fun () -> global_replace "needle" "test" "needlehaystack"; global_replace "needle" "" ""; global_replace "needle" "" "needle"; global_replace "xxx" "yyy" "zzz"; global_replace "test\\([0-9]*\\)" "\\1-foo-\\1" "test100 test200 test"; global_replace "test\\([0-9]*\\)" "'\\-0'" "test100 test200 test"; (* Regrssion test for #129 *) global_replace "\\(X+\\)" "A\\1YY" "XXXXXXZZZZ" ); expect_pass "bounded_split, bounded_full_split" (fun () -> List.iter (fun (re, s, n) -> bounded_full_split re s n; bounded_split re s n) [ ",", "foo,bar,baz", 5 ; ",", "foo,bar,baz", 1 ; ",", "foo,bar,baz", 0 ; ",\\|", "foo,bar|baz", 4 ] ); expect_pass "split, full_split, split_delim" (fun () -> List.iter (fun (re, s) -> split re s; full_split re s; split_delim re s) [ "re", "" ; " ", "foo bar" ; "\b", "one-two three" ; "[0-9]", "One3TwoFive"] ); run_test_suite "test_str" ocaml-re-1.9.0/re.descr000066400000000000000000000005431345204770300146570ustar00rootroot00000000000000RE is a regular expression library for OCaml Pure OCaml regular expressions with: * Perl-style regular expressions (module Re.Perl) * Posix extended regular expressions (module Re.Posix) * Emacs-style regular expressions (module Re.Emacs) * Shell-style file globbing (module Re.Glob) * Compatibility layer for OCaml's built-in Str module (module Re.Str) ocaml-re-1.9.0/re.opam000066400000000000000000000017261345204770300145170ustar00rootroot00000000000000opam-version: "2.0" maintainer: "rudi.grinberg@gmail.com" authors: [ "Jerome Vouillon" "Thomas Gazagnaire" "Anil Madhavapeddy" "Rudi Grinberg" "Gabriel Radanne" ] license: "LGPL-2.0 with OCaml linking exception" homepage: "https://github.com/ocaml/ocaml-re" bug-reports: "https://github.com/ocaml/ocaml-re/issues" dev-repo: "git+https://github.com/ocaml/ocaml-re.git" build: [ ["dune" "subst"] {pinned} ["dune" "build" "-p" name "-j" jobs] ["dune" "runtest" "-p" name "-j" jobs] {with-test} ] depends: [ "ocaml" {>= "4.02"} "dune" {build} "ounit" {with-test} "seq" ] synopsis: "RE is a regular expression library for OCaml" description: """ Pure OCaml regular expressions with: * Perl-style regular expressions (module Re.Perl) * Posix extended regular expressions (module Re.Posix) * Emacs-style regular expressions (module Re.Emacs) * Shell-style file globbing (module Re.Glob) * Compatibility layer for OCaml's built-in Str module (module Re.Str) """