Initial Commit

This commit is contained in:
Elara 2022-05-18 16:28:40 -07:00
commit 406de00b82
19 changed files with 356660 additions and 0 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Arsen Musayelyan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

94
LICENSE-PCRE2 Normal file
View File

@ -0,0 +1,94 @@
PCRE2 LICENCE
-------------
PCRE2 is a library of functions to support regular expressions whose syntax
and semantics are as close as possible to those of the Perl 5 language.
Releases 10.00 and above of PCRE2 are distributed under the terms of the "BSD"
licence, as specified below, with one exemption for certain binary
redistributions. The documentation for PCRE2, supplied in the "doc" directory,
is distributed under the same terms as the software itself. The data in the
testdata directory is not copyrighted and is in the public domain.
The basic library functions are written in C and are freestanding. Also
included in the distribution is a just-in-time compiler that can be used to
optimize pattern matching. This is an optional feature that can be omitted when
the library is built.
THE BASIC LIBRARY FUNCTIONS
---------------------------
Written by: Philip Hazel
Email local part: Philip.Hazel
Email domain: gmail.com
Retired from University of Cambridge Computing Service,
Cambridge, England.
Copyright (c) 1997-2022 University of Cambridge
All rights reserved.
PCRE2 JUST-IN-TIME COMPILATION SUPPORT
--------------------------------------
Written by: Zoltan Herczeg
Email local part: hzmester
Email domain: freemail.hu
Copyright(c) 2010-2022 Zoltan Herczeg
All rights reserved.
STACK-LESS JUST-IN-TIME COMPILER
--------------------------------
Written by: Zoltan Herczeg
Email local part: hzmester
Email domain: freemail.hu
Copyright(c) 2009-2022 Zoltan Herczeg
All rights reserved.
THE "BSD" LICENCE
-----------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notices,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notices, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the University of Cambridge nor the names of any
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
EXEMPTION FOR BINARY LIBRARY-LIKE PACKAGES
------------------------------------------
The second condition in the BSD licence (covering binary redistributions) does
not apply all the way down a chain of software. If binary package A includes
PCRE2, it must respect the condition, but if package B is software that
includes package A, the condition is not imposed on package B unless it uses
PCRE2 independently.
End

42
README.md Normal file
View File

@ -0,0 +1,42 @@
# pcre
This package provides a CGo-free port of the PCRE2 regular expression library. The [lib](lib) directory contains source code automatically translated from PCRE2's C source. This package wraps that code and provides an interface as close as possible to Go's stdlib [regexp](https://pkg.go.dev/regexp) package
---
## Supported GOOS/GOARCH:
- linux/amd64
- linux/386
- linux/arm64
- linux/arm
- linux/riscv64
More OS support is planned.
---
## How to transpile pcre2
In order to transpile pcre2, a Go and C compiler (preferably GCC) will be needed.
- First, install [ccgo](https://pkg.go.dev/modernc.org/ccgo/v3)
- Then, download the pcre source code. It can be found here: https://github.com/PCRE2Project/pcre2.
- Once downloaded, `cd` into the source directory
- Run `./configure`. If cross-compiling, provide the path to the cross-compiler in the `CC` variable, and set `--target` to the target architecture.
- When it completes, there should be a `Makefile` in the directory.
- Run `ccgo -compiledb pcre.json make`. Do not add `-j` arguments to the make command.
- Run the following command (replace items in triangle brackets):
```shell
CC=/usr/bin/gcc ccgo -o pcre2_<os>_<arch>.go -pkgname lib -trace-translation-units -export-externs X -export-defines D -export-fields F -export-structs S -export-typedefs T pcre.json .libs/libpcre2-8.a
```
- If cross-compiling, set the `CCGO_CC` variable to to path of the cross-compiler, and the `CCGO_AR` variable to the path of the cross-compiler's `ar` binary. Also, set `TARGET_GOARCH` to the GOARCH you're targeting and `TARGET_GOOS` to the OS you're targeting.
- Once the command completes, two go files will be created. One will start with `pcre2`, the other with `capi`. Copy both of these to the `lib` directory in this repo.

82
error.go Normal file
View File

@ -0,0 +1,82 @@
package pcre
import (
"fmt"
"unsafe"
"go.arsenm.dev/pcre/lib"
"modernc.org/libc"
"modernc.org/libc/sys/types"
)
var pce pcreError
// pcreError is meant to be manually allocated
// for when pcre requires a pointer to store an error
// such as for Xpcre2_compile_8().
type pcreError struct {
errCode int32
errOffset lib.Tsize_t
}
// allocError manually allocates memory for the
// pcreError struct.
//
// libc.Xfree() should be called on the returned
// pointer once it is no longer needed.
func allocError(tls *libc.TLS) uintptr {
return libc.Xmalloc(tls, types.Size_t(unsafe.Sizeof(pce)))
}
// addErrCodeOffset adds the offset of the error code
// within the pcreError struct to a given pointer
func addErrCodeOffset(p uintptr) uintptr {
ptrOffset := unsafe.Offsetof(pce.errCode)
return p + ptrOffset
}
// addErrOffsetOffset adds the offset of the error
// offset within the pcreError struct to a given pointer
func addErrOffsetOffset(p uintptr) uintptr {
offsetOffset := unsafe.Offsetof(pce.errOffset)
return p + offsetOffset
}
// ptrToError converts the given pointer to a Go error
func ptrToError(tls *libc.TLS, pe uintptr) *PcreError {
eo := *(*pcreError)(unsafe.Pointer(pe))
err := codeToError(tls, eo.errCode)
err.offset = eo.errOffset
return err
}
// codeToError converts the given error code into a Go error
func codeToError(tls *libc.TLS, code int32) *PcreError {
errBuf := make([]byte, 256)
cErrBuf := uintptr(unsafe.Pointer(&errBuf[0]))
// Get the textual error message associated with the code,
// and store it in errBuf.
msgLen := lib.Xpcre2_get_error_message_8(tls, code, cErrBuf, 256)
return &PcreError{0, string(errBuf[:msgLen])}
}
// PcreError represents errors returned
// by underlying pcre2 functions.
type PcreError struct {
offset lib.Tsize_t
errStr string
}
// Error returns the string within the error,
// prepending the offset if it exists.
func (pe *PcreError) Error() string {
if pe.offset == 0 {
return pe.errStr
}
return fmt.Sprintf("offset %d: %s", pe.offset, pe.errStr)
}

14
go.mod Normal file
View File

@ -0,0 +1,14 @@
module go.arsenm.dev/pcre
go 1.18
require modernc.org/libc v1.16.8
require (
github.com/google/uuid v1.3.0 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect
modernc.org/mathutil v1.4.1 // indirect
modernc.org/memory v1.1.1 // indirect
)

55
go.sum Normal file
View File

@ -0,0 +1,55 @@
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=
modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw=
modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A=
modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU=
modernc.org/libc v1.16.8 h1:Ux98PaOMvolgoFX/YwusFOHBnanXdGRmWgI8ciI2z4o=
modernc.org/libc v1.16.8/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.1.1 h1:bDOL0DIDLQv7bWhP3gMvIrnoFw+Eo6F7a2QK9HPDiFU=
modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=

128
lib/capi_linux_386.go Normal file
View File

@ -0,0 +1,128 @@
// Code generated by 'ccgo -o pcre2_linux_386.go -pkgname lib -trace-translation-units -export-externs X -export-defines D -export-fields F -export-structs S -export-typedefs T pcre.json .libs/libpcre2-8.a', DO NOT EDIT.
package lib
var CAPI = map[string]struct{}{
"_pcre2_OP_lengths_8": {},
"_pcre2_auto_possessify_8": {},
"_pcre2_callout_end_delims_8": {},
"_pcre2_callout_start_delims_8": {},
"_pcre2_check_escape_8": {},
"_pcre2_default_compile_context_8": {},
"_pcre2_default_convert_context_8": {},
"_pcre2_default_match_context_8": {},
"_pcre2_default_tables_8": {},
"_pcre2_extuni_8": {},
"_pcre2_find_bracket_8": {},
"_pcre2_hspace_list_8": {},
"_pcre2_is_newline_8": {},
"_pcre2_jit_free_8": {},
"_pcre2_jit_free_rodata_8": {},
"_pcre2_jit_get_size_8": {},
"_pcre2_jit_get_target_8": {},
"_pcre2_memctl_malloc_8": {},
"_pcre2_ord2utf_8": {},
"_pcre2_script_run_8": {},
"_pcre2_strcmp_8": {},
"_pcre2_strcmp_c8_8": {},
"_pcre2_strcpy_c8_8": {},
"_pcre2_strlen_8": {},
"_pcre2_strncmp_8": {},
"_pcre2_strncmp_c8_8": {},
"_pcre2_study_8": {},
"_pcre2_ucd_boolprop_sets_8": {},
"_pcre2_ucd_caseless_sets_8": {},
"_pcre2_ucd_digit_sets_8": {},
"_pcre2_ucd_records_8": {},
"_pcre2_ucd_script_sets_8": {},
"_pcre2_ucd_stage1_8": {},
"_pcre2_ucd_stage2_8": {},
"_pcre2_ucp_gbtable_8": {},
"_pcre2_ucp_gentype_8": {},
"_pcre2_unicode_version_8": {},
"_pcre2_utf8_table1": {},
"_pcre2_utf8_table1_size": {},
"_pcre2_utf8_table2": {},
"_pcre2_utf8_table3": {},
"_pcre2_utf8_table4": {},
"_pcre2_utt_8": {},
"_pcre2_utt_names_8": {},
"_pcre2_utt_size_8": {},
"_pcre2_valid_utf_8": {},
"_pcre2_vspace_list_8": {},
"_pcre2_was_newline_8": {},
"_pcre2_xclass_8": {},
"pcre2_callout_enumerate_8": {},
"pcre2_code_copy_8": {},
"pcre2_code_copy_with_tables_8": {},
"pcre2_code_free_8": {},
"pcre2_compile_8": {},
"pcre2_compile_context_copy_8": {},
"pcre2_compile_context_create_8": {},
"pcre2_compile_context_free_8": {},
"pcre2_config_8": {},
"pcre2_convert_context_copy_8": {},
"pcre2_convert_context_create_8": {},
"pcre2_convert_context_free_8": {},
"pcre2_converted_pattern_free_8": {},
"pcre2_dfa_match_8": {},
"pcre2_general_context_copy_8": {},
"pcre2_general_context_create_8": {},
"pcre2_general_context_free_8": {},
"pcre2_get_error_message_8": {},
"pcre2_get_mark_8": {},
"pcre2_get_match_data_size_8": {},
"pcre2_get_ovector_count_8": {},
"pcre2_get_ovector_pointer_8": {},
"pcre2_get_startchar_8": {},
"pcre2_jit_compile_8": {},
"pcre2_jit_free_unused_memory_8": {},
"pcre2_jit_match_8": {},
"pcre2_jit_stack_assign_8": {},
"pcre2_jit_stack_create_8": {},
"pcre2_jit_stack_free_8": {},
"pcre2_maketables_8": {},
"pcre2_maketables_free_8": {},
"pcre2_match_8": {},
"pcre2_match_context_copy_8": {},
"pcre2_match_context_create_8": {},
"pcre2_match_context_free_8": {},
"pcre2_match_data_create_8": {},
"pcre2_match_data_create_from_pattern_8": {},
"pcre2_match_data_free_8": {},
"pcre2_pattern_convert_8": {},
"pcre2_pattern_info_8": {},
"pcre2_serialize_decode_8": {},
"pcre2_serialize_encode_8": {},
"pcre2_serialize_free_8": {},
"pcre2_serialize_get_number_of_codes_8": {},
"pcre2_set_bsr_8": {},
"pcre2_set_callout_8": {},
"pcre2_set_character_tables_8": {},
"pcre2_set_compile_extra_options_8": {},
"pcre2_set_compile_recursion_guard_8": {},
"pcre2_set_depth_limit_8": {},
"pcre2_set_glob_escape_8": {},
"pcre2_set_glob_separator_8": {},
"pcre2_set_heap_limit_8": {},
"pcre2_set_match_limit_8": {},
"pcre2_set_max_pattern_length_8": {},
"pcre2_set_newline_8": {},
"pcre2_set_offset_limit_8": {},
"pcre2_set_parens_nest_limit_8": {},
"pcre2_set_recursion_limit_8": {},
"pcre2_set_recursion_memory_management_8": {},
"pcre2_set_substitute_callout_8": {},
"pcre2_substitute_8": {},
"pcre2_substring_copy_byname_8": {},
"pcre2_substring_copy_bynumber_8": {},
"pcre2_substring_free_8": {},
"pcre2_substring_get_byname_8": {},
"pcre2_substring_get_bynumber_8": {},
"pcre2_substring_length_byname_8": {},
"pcre2_substring_length_bynumber_8": {},
"pcre2_substring_list_free_8": {},
"pcre2_substring_list_get_8": {},
"pcre2_substring_nametable_scan_8": {},
"pcre2_substring_number_from_name_8": {},
}

128
lib/capi_linux_amd64.go Normal file
View File

@ -0,0 +1,128 @@
// Code generated by 'ccgo -o pcre2.go -pkgname lib -trace-translation-units -export-externs X -export-defines D -export-fields F -export-structs S -export-typedefs T pcre.json .libs/libpcre2-8.a', DO NOT EDIT.
package lib
var CAPI = map[string]struct{}{
"_pcre2_OP_lengths_8": {},
"_pcre2_auto_possessify_8": {},
"_pcre2_callout_end_delims_8": {},
"_pcre2_callout_start_delims_8": {},
"_pcre2_check_escape_8": {},
"_pcre2_default_compile_context_8": {},
"_pcre2_default_convert_context_8": {},
"_pcre2_default_match_context_8": {},
"_pcre2_default_tables_8": {},
"_pcre2_extuni_8": {},
"_pcre2_find_bracket_8": {},
"_pcre2_hspace_list_8": {},
"_pcre2_is_newline_8": {},
"_pcre2_jit_free_8": {},
"_pcre2_jit_free_rodata_8": {},
"_pcre2_jit_get_size_8": {},
"_pcre2_jit_get_target_8": {},
"_pcre2_memctl_malloc_8": {},
"_pcre2_ord2utf_8": {},
"_pcre2_script_run_8": {},
"_pcre2_strcmp_8": {},
"_pcre2_strcmp_c8_8": {},
"_pcre2_strcpy_c8_8": {},
"_pcre2_strlen_8": {},
"_pcre2_strncmp_8": {},
"_pcre2_strncmp_c8_8": {},
"_pcre2_study_8": {},
"_pcre2_ucd_boolprop_sets_8": {},
"_pcre2_ucd_caseless_sets_8": {},
"_pcre2_ucd_digit_sets_8": {},
"_pcre2_ucd_records_8": {},
"_pcre2_ucd_script_sets_8": {},
"_pcre2_ucd_stage1_8": {},
"_pcre2_ucd_stage2_8": {},
"_pcre2_ucp_gbtable_8": {},
"_pcre2_ucp_gentype_8": {},
"_pcre2_unicode_version_8": {},
"_pcre2_utf8_table1": {},
"_pcre2_utf8_table1_size": {},
"_pcre2_utf8_table2": {},
"_pcre2_utf8_table3": {},
"_pcre2_utf8_table4": {},
"_pcre2_utt_8": {},
"_pcre2_utt_names_8": {},
"_pcre2_utt_size_8": {},
"_pcre2_valid_utf_8": {},
"_pcre2_vspace_list_8": {},
"_pcre2_was_newline_8": {},
"_pcre2_xclass_8": {},
"pcre2_callout_enumerate_8": {},
"pcre2_code_copy_8": {},
"pcre2_code_copy_with_tables_8": {},
"pcre2_code_free_8": {},
"pcre2_compile_8": {},
"pcre2_compile_context_copy_8": {},
"pcre2_compile_context_create_8": {},
"pcre2_compile_context_free_8": {},
"pcre2_config_8": {},
"pcre2_convert_context_copy_8": {},
"pcre2_convert_context_create_8": {},
"pcre2_convert_context_free_8": {},
"pcre2_converted_pattern_free_8": {},
"pcre2_dfa_match_8": {},
"pcre2_general_context_copy_8": {},
"pcre2_general_context_create_8": {},
"pcre2_general_context_free_8": {},
"pcre2_get_error_message_8": {},
"pcre2_get_mark_8": {},
"pcre2_get_match_data_size_8": {},
"pcre2_get_ovector_count_8": {},
"pcre2_get_ovector_pointer_8": {},
"pcre2_get_startchar_8": {},
"pcre2_jit_compile_8": {},
"pcre2_jit_free_unused_memory_8": {},
"pcre2_jit_match_8": {},
"pcre2_jit_stack_assign_8": {},
"pcre2_jit_stack_create_8": {},
"pcre2_jit_stack_free_8": {},
"pcre2_maketables_8": {},
"pcre2_maketables_free_8": {},
"pcre2_match_8": {},
"pcre2_match_context_copy_8": {},
"pcre2_match_context_create_8": {},
"pcre2_match_context_free_8": {},
"pcre2_match_data_create_8": {},
"pcre2_match_data_create_from_pattern_8": {},
"pcre2_match_data_free_8": {},
"pcre2_pattern_convert_8": {},
"pcre2_pattern_info_8": {},
"pcre2_serialize_decode_8": {},
"pcre2_serialize_encode_8": {},
"pcre2_serialize_free_8": {},
"pcre2_serialize_get_number_of_codes_8": {},
"pcre2_set_bsr_8": {},
"pcre2_set_callout_8": {},
"pcre2_set_character_tables_8": {},
"pcre2_set_compile_extra_options_8": {},
"pcre2_set_compile_recursion_guard_8": {},
"pcre2_set_depth_limit_8": {},
"pcre2_set_glob_escape_8": {},
"pcre2_set_glob_separator_8": {},
"pcre2_set_heap_limit_8": {},
"pcre2_set_match_limit_8": {},
"pcre2_set_max_pattern_length_8": {},
"pcre2_set_newline_8": {},
"pcre2_set_offset_limit_8": {},
"pcre2_set_parens_nest_limit_8": {},
"pcre2_set_recursion_limit_8": {},
"pcre2_set_recursion_memory_management_8": {},
"pcre2_set_substitute_callout_8": {},
"pcre2_substitute_8": {},
"pcre2_substring_copy_byname_8": {},
"pcre2_substring_copy_bynumber_8": {},
"pcre2_substring_free_8": {},
"pcre2_substring_get_byname_8": {},
"pcre2_substring_get_bynumber_8": {},
"pcre2_substring_length_byname_8": {},
"pcre2_substring_length_bynumber_8": {},
"pcre2_substring_list_free_8": {},
"pcre2_substring_list_get_8": {},
"pcre2_substring_nametable_scan_8": {},
"pcre2_substring_number_from_name_8": {},
}

128
lib/capi_linux_arm.go Normal file
View File

@ -0,0 +1,128 @@
// Code generated by 'ccgo -o pcre2_linux_arm.go -pkgname lib -trace-translation-units -export-externs X -export-defines D -export-fields F -export-structs S -export-typedefs T pcre.json .libs/libpcre2-8.a', DO NOT EDIT.
package lib
var CAPI = map[string]struct{}{
"_pcre2_OP_lengths_8": {},
"_pcre2_auto_possessify_8": {},
"_pcre2_callout_end_delims_8": {},
"_pcre2_callout_start_delims_8": {},
"_pcre2_check_escape_8": {},
"_pcre2_default_compile_context_8": {},
"_pcre2_default_convert_context_8": {},
"_pcre2_default_match_context_8": {},
"_pcre2_default_tables_8": {},
"_pcre2_extuni_8": {},
"_pcre2_find_bracket_8": {},
"_pcre2_hspace_list_8": {},
"_pcre2_is_newline_8": {},
"_pcre2_jit_free_8": {},
"_pcre2_jit_free_rodata_8": {},
"_pcre2_jit_get_size_8": {},
"_pcre2_jit_get_target_8": {},
"_pcre2_memctl_malloc_8": {},
"_pcre2_ord2utf_8": {},
"_pcre2_script_run_8": {},
"_pcre2_strcmp_8": {},
"_pcre2_strcmp_c8_8": {},
"_pcre2_strcpy_c8_8": {},
"_pcre2_strlen_8": {},
"_pcre2_strncmp_8": {},
"_pcre2_strncmp_c8_8": {},
"_pcre2_study_8": {},
"_pcre2_ucd_boolprop_sets_8": {},
"_pcre2_ucd_caseless_sets_8": {},
"_pcre2_ucd_digit_sets_8": {},
"_pcre2_ucd_records_8": {},
"_pcre2_ucd_script_sets_8": {},
"_pcre2_ucd_stage1_8": {},
"_pcre2_ucd_stage2_8": {},
"_pcre2_ucp_gbtable_8": {},
"_pcre2_ucp_gentype_8": {},
"_pcre2_unicode_version_8": {},
"_pcre2_utf8_table1": {},
"_pcre2_utf8_table1_size": {},
"_pcre2_utf8_table2": {},
"_pcre2_utf8_table3": {},
"_pcre2_utf8_table4": {},
"_pcre2_utt_8": {},
"_pcre2_utt_names_8": {},
"_pcre2_utt_size_8": {},
"_pcre2_valid_utf_8": {},
"_pcre2_vspace_list_8": {},
"_pcre2_was_newline_8": {},
"_pcre2_xclass_8": {},
"pcre2_callout_enumerate_8": {},
"pcre2_code_copy_8": {},
"pcre2_code_copy_with_tables_8": {},
"pcre2_code_free_8": {},
"pcre2_compile_8": {},
"pcre2_compile_context_copy_8": {},
"pcre2_compile_context_create_8": {},
"pcre2_compile_context_free_8": {},
"pcre2_config_8": {},
"pcre2_convert_context_copy_8": {},
"pcre2_convert_context_create_8": {},
"pcre2_convert_context_free_8": {},
"pcre2_converted_pattern_free_8": {},
"pcre2_dfa_match_8": {},
"pcre2_general_context_copy_8": {},
"pcre2_general_context_create_8": {},
"pcre2_general_context_free_8": {},
"pcre2_get_error_message_8": {},
"pcre2_get_mark_8": {},
"pcre2_get_match_data_size_8": {},
"pcre2_get_ovector_count_8": {},
"pcre2_get_ovector_pointer_8": {},
"pcre2_get_startchar_8": {},
"pcre2_jit_compile_8": {},
"pcre2_jit_free_unused_memory_8": {},
"pcre2_jit_match_8": {},
"pcre2_jit_stack_assign_8": {},
"pcre2_jit_stack_create_8": {},
"pcre2_jit_stack_free_8": {},
"pcre2_maketables_8": {},
"pcre2_maketables_free_8": {},
"pcre2_match_8": {},
"pcre2_match_context_copy_8": {},
"pcre2_match_context_create_8": {},
"pcre2_match_context_free_8": {},
"pcre2_match_data_create_8": {},
"pcre2_match_data_create_from_pattern_8": {},
"pcre2_match_data_free_8": {},
"pcre2_pattern_convert_8": {},
"pcre2_pattern_info_8": {},
"pcre2_serialize_decode_8": {},
"pcre2_serialize_encode_8": {},
"pcre2_serialize_free_8": {},
"pcre2_serialize_get_number_of_codes_8": {},
"pcre2_set_bsr_8": {},
"pcre2_set_callout_8": {},
"pcre2_set_character_tables_8": {},
"pcre2_set_compile_extra_options_8": {},
"pcre2_set_compile_recursion_guard_8": {},
"pcre2_set_depth_limit_8": {},
"pcre2_set_glob_escape_8": {},
"pcre2_set_glob_separator_8": {},
"pcre2_set_heap_limit_8": {},
"pcre2_set_match_limit_8": {},
"pcre2_set_max_pattern_length_8": {},
"pcre2_set_newline_8": {},
"pcre2_set_offset_limit_8": {},
"pcre2_set_parens_nest_limit_8": {},
"pcre2_set_recursion_limit_8": {},
"pcre2_set_recursion_memory_management_8": {},
"pcre2_set_substitute_callout_8": {},
"pcre2_substitute_8": {},
"pcre2_substring_copy_byname_8": {},
"pcre2_substring_copy_bynumber_8": {},
"pcre2_substring_free_8": {},
"pcre2_substring_get_byname_8": {},
"pcre2_substring_get_bynumber_8": {},
"pcre2_substring_length_byname_8": {},
"pcre2_substring_length_bynumber_8": {},
"pcre2_substring_list_free_8": {},
"pcre2_substring_list_get_8": {},
"pcre2_substring_nametable_scan_8": {},
"pcre2_substring_number_from_name_8": {},
}

128
lib/capi_linux_arm64.go Normal file
View File

@ -0,0 +1,128 @@
// Code generated by 'ccgo -o pcre2.go -pkgname lib -trace-translation-units -export-externs X -export-defines D -export-fields F -export-structs S -export-typedefs T pcre.json .libs/libpcre2-8.a', DO NOT EDIT.
package lib
var CAPI = map[string]struct{}{
"_pcre2_OP_lengths_8": {},
"_pcre2_auto_possessify_8": {},
"_pcre2_callout_end_delims_8": {},
"_pcre2_callout_start_delims_8": {},
"_pcre2_check_escape_8": {},
"_pcre2_default_compile_context_8": {},
"_pcre2_default_convert_context_8": {},
"_pcre2_default_match_context_8": {},
"_pcre2_default_tables_8": {},
"_pcre2_extuni_8": {},
"_pcre2_find_bracket_8": {},
"_pcre2_hspace_list_8": {},
"_pcre2_is_newline_8": {},
"_pcre2_jit_free_8": {},
"_pcre2_jit_free_rodata_8": {},
"_pcre2_jit_get_size_8": {},
"_pcre2_jit_get_target_8": {},
"_pcre2_memctl_malloc_8": {},
"_pcre2_ord2utf_8": {},
"_pcre2_script_run_8": {},
"_pcre2_strcmp_8": {},
"_pcre2_strcmp_c8_8": {},
"_pcre2_strcpy_c8_8": {},
"_pcre2_strlen_8": {},
"_pcre2_strncmp_8": {},
"_pcre2_strncmp_c8_8": {},
"_pcre2_study_8": {},
"_pcre2_ucd_boolprop_sets_8": {},
"_pcre2_ucd_caseless_sets_8": {},
"_pcre2_ucd_digit_sets_8": {},
"_pcre2_ucd_records_8": {},
"_pcre2_ucd_script_sets_8": {},
"_pcre2_ucd_stage1_8": {},
"_pcre2_ucd_stage2_8": {},
"_pcre2_ucp_gbtable_8": {},
"_pcre2_ucp_gentype_8": {},
"_pcre2_unicode_version_8": {},
"_pcre2_utf8_table1": {},
"_pcre2_utf8_table1_size": {},
"_pcre2_utf8_table2": {},
"_pcre2_utf8_table3": {},
"_pcre2_utf8_table4": {},
"_pcre2_utt_8": {},
"_pcre2_utt_names_8": {},
"_pcre2_utt_size_8": {},
"_pcre2_valid_utf_8": {},
"_pcre2_vspace_list_8": {},
"_pcre2_was_newline_8": {},
"_pcre2_xclass_8": {},
"pcre2_callout_enumerate_8": {},
"pcre2_code_copy_8": {},
"pcre2_code_copy_with_tables_8": {},
"pcre2_code_free_8": {},
"pcre2_compile_8": {},
"pcre2_compile_context_copy_8": {},
"pcre2_compile_context_create_8": {},
"pcre2_compile_context_free_8": {},
"pcre2_config_8": {},
"pcre2_convert_context_copy_8": {},
"pcre2_convert_context_create_8": {},
"pcre2_convert_context_free_8": {},
"pcre2_converted_pattern_free_8": {},
"pcre2_dfa_match_8": {},
"pcre2_general_context_copy_8": {},
"pcre2_general_context_create_8": {},
"pcre2_general_context_free_8": {},
"pcre2_get_error_message_8": {},
"pcre2_get_mark_8": {},
"pcre2_get_match_data_size_8": {},
"pcre2_get_ovector_count_8": {},
"pcre2_get_ovector_pointer_8": {},
"pcre2_get_startchar_8": {},
"pcre2_jit_compile_8": {},
"pcre2_jit_free_unused_memory_8": {},
"pcre2_jit_match_8": {},
"pcre2_jit_stack_assign_8": {},
"pcre2_jit_stack_create_8": {},
"pcre2_jit_stack_free_8": {},
"pcre2_maketables_8": {},
"pcre2_maketables_free_8": {},
"pcre2_match_8": {},
"pcre2_match_context_copy_8": {},
"pcre2_match_context_create_8": {},
"pcre2_match_context_free_8": {},
"pcre2_match_data_create_8": {},
"pcre2_match_data_create_from_pattern_8": {},
"pcre2_match_data_free_8": {},
"pcre2_pattern_convert_8": {},
"pcre2_pattern_info_8": {},
"pcre2_serialize_decode_8": {},
"pcre2_serialize_encode_8": {},
"pcre2_serialize_free_8": {},
"pcre2_serialize_get_number_of_codes_8": {},
"pcre2_set_bsr_8": {},
"pcre2_set_callout_8": {},
"pcre2_set_character_tables_8": {},
"pcre2_set_compile_extra_options_8": {},
"pcre2_set_compile_recursion_guard_8": {},
"pcre2_set_depth_limit_8": {},
"pcre2_set_glob_escape_8": {},
"pcre2_set_glob_separator_8": {},
"pcre2_set_heap_limit_8": {},
"pcre2_set_match_limit_8": {},
"pcre2_set_max_pattern_length_8": {},
"pcre2_set_newline_8": {},
"pcre2_set_offset_limit_8": {},
"pcre2_set_parens_nest_limit_8": {},
"pcre2_set_recursion_limit_8": {},
"pcre2_set_recursion_memory_management_8": {},
"pcre2_set_substitute_callout_8": {},
"pcre2_substitute_8": {},
"pcre2_substring_copy_byname_8": {},
"pcre2_substring_copy_bynumber_8": {},
"pcre2_substring_free_8": {},
"pcre2_substring_get_byname_8": {},
"pcre2_substring_get_bynumber_8": {},
"pcre2_substring_length_byname_8": {},
"pcre2_substring_length_bynumber_8": {},
"pcre2_substring_list_free_8": {},
"pcre2_substring_list_get_8": {},
"pcre2_substring_nametable_scan_8": {},
"pcre2_substring_number_from_name_8": {},
}

128
lib/capi_linux_riscv64.go Normal file
View File

@ -0,0 +1,128 @@
// Code generated by 'ccgo -o pcre2_linux_riscv64.go -pkgname lib -trace-translation-units -export-externs X -export-defines D -export-fields F -export-structs S -export-typedefs T pcre.json .libs/libpcre2-8.a', DO NOT EDIT.
package lib
var CAPI = map[string]struct{}{
"_pcre2_OP_lengths_8": {},
"_pcre2_auto_possessify_8": {},
"_pcre2_callout_end_delims_8": {},
"_pcre2_callout_start_delims_8": {},
"_pcre2_check_escape_8": {},
"_pcre2_default_compile_context_8": {},
"_pcre2_default_convert_context_8": {},
"_pcre2_default_match_context_8": {},
"_pcre2_default_tables_8": {},
"_pcre2_extuni_8": {},
"_pcre2_find_bracket_8": {},
"_pcre2_hspace_list_8": {},
"_pcre2_is_newline_8": {},
"_pcre2_jit_free_8": {},
"_pcre2_jit_free_rodata_8": {},
"_pcre2_jit_get_size_8": {},
"_pcre2_jit_get_target_8": {},
"_pcre2_memctl_malloc_8": {},
"_pcre2_ord2utf_8": {},
"_pcre2_script_run_8": {},
"_pcre2_strcmp_8": {},
"_pcre2_strcmp_c8_8": {},
"_pcre2_strcpy_c8_8": {},
"_pcre2_strlen_8": {},
"_pcre2_strncmp_8": {},
"_pcre2_strncmp_c8_8": {},
"_pcre2_study_8": {},
"_pcre2_ucd_boolprop_sets_8": {},
"_pcre2_ucd_caseless_sets_8": {},
"_pcre2_ucd_digit_sets_8": {},
"_pcre2_ucd_records_8": {},
"_pcre2_ucd_script_sets_8": {},
"_pcre2_ucd_stage1_8": {},
"_pcre2_ucd_stage2_8": {},
"_pcre2_ucp_gbtable_8": {},
"_pcre2_ucp_gentype_8": {},
"_pcre2_unicode_version_8": {},
"_pcre2_utf8_table1": {},
"_pcre2_utf8_table1_size": {},
"_pcre2_utf8_table2": {},
"_pcre2_utf8_table3": {},
"_pcre2_utf8_table4": {},
"_pcre2_utt_8": {},
"_pcre2_utt_names_8": {},
"_pcre2_utt_size_8": {},
"_pcre2_valid_utf_8": {},
"_pcre2_vspace_list_8": {},
"_pcre2_was_newline_8": {},
"_pcre2_xclass_8": {},
"pcre2_callout_enumerate_8": {},
"pcre2_code_copy_8": {},
"pcre2_code_copy_with_tables_8": {},
"pcre2_code_free_8": {},
"pcre2_compile_8": {},
"pcre2_compile_context_copy_8": {},
"pcre2_compile_context_create_8": {},
"pcre2_compile_context_free_8": {},
"pcre2_config_8": {},
"pcre2_convert_context_copy_8": {},
"pcre2_convert_context_create_8": {},
"pcre2_convert_context_free_8": {},
"pcre2_converted_pattern_free_8": {},
"pcre2_dfa_match_8": {},
"pcre2_general_context_copy_8": {},
"pcre2_general_context_create_8": {},
"pcre2_general_context_free_8": {},
"pcre2_get_error_message_8": {},
"pcre2_get_mark_8": {},
"pcre2_get_match_data_size_8": {},
"pcre2_get_ovector_count_8": {},
"pcre2_get_ovector_pointer_8": {},
"pcre2_get_startchar_8": {},
"pcre2_jit_compile_8": {},
"pcre2_jit_free_unused_memory_8": {},
"pcre2_jit_match_8": {},
"pcre2_jit_stack_assign_8": {},
"pcre2_jit_stack_create_8": {},
"pcre2_jit_stack_free_8": {},
"pcre2_maketables_8": {},
"pcre2_maketables_free_8": {},
"pcre2_match_8": {},
"pcre2_match_context_copy_8": {},
"pcre2_match_context_create_8": {},
"pcre2_match_context_free_8": {},
"pcre2_match_data_create_8": {},
"pcre2_match_data_create_from_pattern_8": {},
"pcre2_match_data_free_8": {},
"pcre2_pattern_convert_8": {},
"pcre2_pattern_info_8": {},
"pcre2_serialize_decode_8": {},
"pcre2_serialize_encode_8": {},
"pcre2_serialize_free_8": {},
"pcre2_serialize_get_number_of_codes_8": {},
"pcre2_set_bsr_8": {},
"pcre2_set_callout_8": {},
"pcre2_set_character_tables_8": {},
"pcre2_set_compile_extra_options_8": {},
"pcre2_set_compile_recursion_guard_8": {},
"pcre2_set_depth_limit_8": {},
"pcre2_set_glob_escape_8": {},
"pcre2_set_glob_separator_8": {},
"pcre2_set_heap_limit_8": {},
"pcre2_set_match_limit_8": {},
"pcre2_set_max_pattern_length_8": {},
"pcre2_set_newline_8": {},
"pcre2_set_offset_limit_8": {},
"pcre2_set_parens_nest_limit_8": {},
"pcre2_set_recursion_limit_8": {},
"pcre2_set_recursion_memory_management_8": {},
"pcre2_set_substitute_callout_8": {},
"pcre2_substitute_8": {},
"pcre2_substring_copy_byname_8": {},
"pcre2_substring_copy_bynumber_8": {},
"pcre2_substring_free_8": {},
"pcre2_substring_get_byname_8": {},
"pcre2_substring_get_bynumber_8": {},
"pcre2_substring_length_byname_8": {},
"pcre2_substring_length_bynumber_8": {},
"pcre2_substring_list_free_8": {},
"pcre2_substring_list_get_8": {},
"pcre2_substring_nametable_scan_8": {},
"pcre2_substring_number_from_name_8": {},
}

70944
lib/pcre2_linux_386.go Normal file

File diff suppressed because one or more lines are too long

70962
lib/pcre2_linux_amd64.go Normal file

File diff suppressed because one or more lines are too long

70944
lib/pcre2_linux_arm.go Normal file

File diff suppressed because one or more lines are too long

70962
lib/pcre2_linux_arm64.go Normal file

File diff suppressed because one or more lines are too long

70961
lib/pcre2_linux_riscv64.go Normal file

File diff suppressed because one or more lines are too long

665
pcre.go Normal file
View File

@ -0,0 +1,665 @@
// Package pcre is a library that provides pcre2 regular expressions
// in pure Go, allowing for features such as cross-compiling.
//
// The lib directory contains source code automatically translated from
// pcre2's C source code for each supported architecture and/or OS.
// This package wraps the automatically-translated source to provide a
// safe interface as close to Go's regexp library as possible.
package pcre
import (
"os"
"runtime"
"strconv"
"sync"
"unsafe"
"go.arsenm.dev/pcre/lib"
"modernc.org/libc"
)
// Regexp represents a pcre2 regular expression
type Regexp struct {
mtx *sync.Mutex
expr string
re uintptr
tls *libc.TLS
}
// Compile runs CompileOpts with no options.
//
// Close() should be called on the returned expression
// once it is no longer needed.
func Compile(pattern string) (*Regexp, error) {
return CompileOpts(pattern, 0)
}
// CompileOpts compiles the provided pattern using the given options.
//
// Close() should be called on the returned expression
// once it is no longer needed.
func CompileOpts(pattern string, options CompileOption) (*Regexp, error) {
tls := libc.NewTLS()
// Get C string of pattern
cPattern, err := libc.CString(pattern)
if err != nil {
return nil, err
}
// Free the string when done
defer libc.Xfree(tls, cPattern)
// Allocate new error
cErr := allocError(tls)
// Free error when done
defer libc.Xfree(tls, cErr)
// Get error offsets
errPtr := addErrCodeOffset(cErr)
errOffsetPtr := addErrOffsetOffset(cErr)
// Convert pattern length to size_t type
cPatLen := lib.Tsize_t(len(pattern))
// Compile expression
r := lib.Xpcre2_compile_8(tls, cPattern, cPatLen, uint32(options), errPtr, errOffsetPtr, 0)
if r == 0 {
return nil, ptrToError(tls, cErr)
}
// Create regexp instance
regex := Regexp{
expr: pattern,
mtx: &sync.Mutex{},
re: r,
tls: tls,
}
// Make sure resources are freed if GC collects the
// regular expression.
runtime.SetFinalizer(&regex, func(r *Regexp) error {
return r.Close()
})
return &regex, nil
}
// MustCompile compiles the given pattern and panics
// if there was an error
//
// Close() should be called on the returned expression
// once it is no longer needed.
func MustCompile(pattern string) *Regexp {
rgx, err := Compile(pattern)
if err != nil {
panic(err)
}
return rgx
}
// MustCompileOpts compiles the given pattern with the given
// options and panics if there was an error.
//
// Close() should be called on the returned expression
// once it is no longer needed.
func MustCompileOpts(pattern string, options CompileOption) *Regexp {
rgx, err := CompileOpts(pattern, options)
if err != nil {
panic(err)
}
return rgx
}
// Find returns the leftmost match of the regular expression.
// A return value of nil indicates no match.
func (r *Regexp) Find(b []byte) []byte {
matches, err := r.match(b, 0, false)
if err != nil {
panic(err)
}
if len(matches) == 0 {
return nil
}
match := matches[0]
return b[match[0]:match[1]]
}
// FindIndex returns a two-element slice of integers
// representing the location of the leftmost match of the
// regular expression.
func (r *Regexp) FindIndex(b []byte) []int {
matches, err := r.match(b, 0, false)
if err != nil {
panic(err)
}
if len(matches) == 0 {
return nil
}
match := matches[0]
return []int{int(match[0]), int(match[1])}
}
// FindAll returns all matches of the regular expression.
// A return value of nil indicates no match.
func (r *Regexp) FindAll(b []byte, n int) [][]byte {
matches, err := r.match(b, 0, true)
if err != nil {
panic(err)
}
if len(matches) == 0 || n == 0 {
return nil
}
if n > 0 && len(matches) > n {
matches = matches[:n]
}
var out [][]byte
for _, match := range matches {
out = append(out, b[match[0]:match[1]])
}
return out
}
// FindAll returns indices of all matches of the
// regular expression. A return value of nil indicates
// no match.
func (r *Regexp) FindAllIndex(b []byte, n int) [][]int {
matches, err := r.match(b, 0, true)
if err != nil {
panic(err)
}
if len(matches) == 0 || n == 0 {
return nil
}
if n > 0 && len(matches) > n {
matches = matches[:n]
}
var out [][]int
for _, match := range matches {
out = append(out, []int{int(match[0]), int(match[1])})
}
return out
}
// FindSubmatch returns a slice containing the match as the
// first element, and the submatches as the subsequent elements.
func (r *Regexp) FindSubmatch(b []byte) [][]byte {
matches, err := r.match(b, 0, false)
if err != nil {
panic(err)
}
if len(matches) == 0 {
return nil
}
match := matches[0]
out := make([][]byte, len(match))
for i := 0; i < len(match); i += 2 {
out[i] = b[match[i]:match[i+1]]
}
return out
}
// FindSubmatchIndex returns a slice of index pairs representing
// the match and submatches, if any.
func (r *Regexp) FindSubmatchIndex(b []byte) []int {
matches, err := r.match(b, 0, false)
if err != nil {
panic(err)
}
if len(matches) == 0 {
return nil
}
match := matches[0]
out := make([]int, len(match))
for index, offset := range match {
out[index] = int(offset)
}
return out
}
// FindAllSubmatch returns a slice of all matches and submatches
// of the regular expression. It will return no more than n matches.
// If n < 0, it will return all matches.
func (r *Regexp) FindAllSubmatch(b []byte, n int) [][][]byte {
matches, err := r.match(b, 0, true)
if err != nil {
panic(err)
}
if len(matches) == 0 || n == 0 {
return nil
}
if n > 0 && len(matches) > n {
matches = matches[:n]
}
out := make([][][]byte, len(matches))
for index, match := range matches {
var outMatch [][]byte
for i := 0; i < len(match); i += 2 {
outMatch = append(outMatch, b[match[i]:match[i+1]])
}
out[index] = outMatch
}
return out
}
// FindAllSubmatch returns a slice of all indeces representing the
// locations of matches and submatches, if any, of the regular expression.
// It will return no more than n matches. If n < 0, it will return all matches.
func (r *Regexp) FindAllSubmatchIndex(b []byte, n int) [][]int {
matches, err := r.match(b, 0, true)
if err != nil {
panic(err)
}
if len(matches) == 0 || n == 0 {
return nil
}
if n > 0 && len(matches) > n {
matches = matches[:n]
}
out := make([][]int, len(matches))
for index, match := range matches {
offsets := make([]int, len(match))
for index, offset := range match {
offsets[index] = int(offset)
}
out[index] = offsets
}
return out
}
// FindString is the String version of Find
func (r *Regexp) FindString(s string) string {
return string(r.Find([]byte(s)))
}
// FindStringIndex is the String version of FindIndex
func (r *Regexp) FindStringIndex(s string) []int {
return r.FindIndex([]byte(s))
}
// FinAllString is the String version of FindAll
func (r *Regexp) FindAllString(s string, n int) []string {
matches := r.FindAll([]byte(s), n)
out := make([]string, len(matches))
for index, match := range matches {
out[index] = string(match)
}
return out
}
// FindAllStringIndex is the String version of FindIndex
func (r *Regexp) FindAllStringIndex(s string, n int) [][]int {
return r.FindAllIndex([]byte(s), n)
}
// FindStringSubmatch is the string version of FindSubmatch
func (r *Regexp) FindStringSubmatch(s string) []string {
matches := r.FindSubmatch([]byte(s))
out := make([]string, len(matches))
for index, match := range matches {
out[index] = string(match)
}
return out
}
// FindStringSubmatchIndex is the String version of FindSubmatchIndex
func (r *Regexp) FindStringSubmatchIndex(s string) []int {
return r.FindSubmatchIndex([]byte(s))
}
// FindAllStringSubmatch is the String version of FindAllSubmatch
func (r *Regexp) FindAllStringSubmatch(s string, n int) [][]string {
matches := r.FindAllSubmatch([]byte(s), n)
out := make([][]string, len(matches))
for index, match := range matches {
outMatch := make([]string, len(match))
for index, byteMatch := range match {
outMatch[index] = string(byteMatch)
}
out[index] = outMatch
}
return out
}
// FindAllStringSubmatchIndex is the String version of FindAllSubmatchIndex
func (r *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int {
return r.FindAllSubmatchIndex([]byte(s), n)
}
// Match reports whether b contains a match of the regular expression
func (r *Regexp) Match(b []byte) bool {
return r.Find(b) != nil
}
// MatchString is the String version of Match
func (r *Regexp) MatchString(s string) bool {
return r.Find([]byte(s)) != nil
}
// NumSubexp returns the number of parenthesized subexpressions
// in the regular expression.
func (r *Regexp) NumSubexp() int {
return int(r.patternInfo(lib.DPCRE2_INFO_CAPTURECOUNT))
}
// ReplaceAll returns a copy of src, replacing matches of the
// regular expression with the replacement text repl.
// Inside repl, $ signs are interpreted as in Expand,
// so for instance $1 represents the text of the first
// submatch.
func (r *Regexp) ReplaceAll(src, repl []byte) []byte {
matches, err := r.match(src, 0, true)
if err != nil {
panic(err)
}
if len(matches) == 0 {
return nil
}
out := make([]byte, len(src))
copy(out, src)
var diff int64
for _, match := range matches {
replStr := os.Expand(string(repl), func(s string) string {
i, err := strconv.Atoi(s)
if err != nil {
return ""
}
// If there given match does not exist, return empty string
if i == 0 || len(match) < (2*i)+1 {
return ""
}
// Return match
return string(src[match[2*i]:match[(2*i)+1]])
})
// Replace replacement string with expanded string
repl := []byte(replStr)
// Replace bytes with new replacement string
diff, out = replaceBytes(out, repl, match[0], match[1], diff)
}
return out
}
// ReplaceAllFunc returns a copy of src in which all matches of the
// regular expression have been replaced by the return value of function
// repl applied to the matched byte slice. The replacement returned by
// repl is substituted directly, without using Expand.
func (r *Regexp) ReplaceAllFunc(src []byte, repl func([]byte) []byte) []byte {
matches, err := r.match(src, 0, true)
if err != nil {
panic(err)
}
if len(matches) == 0 {
return nil
}
out := make([]byte, len(src))
copy(out, src)
var diff int64
for _, match := range matches {
replBytes := repl(src[match[0]:match[1]])
diff, out = replaceBytes(out, replBytes, match[0], match[1], diff)
}
return out
}
// ReplaceAllLiteral returns a copy of src, replacing matches of
// the regular expression with the replacement bytes repl.
// The replacement is substituted directly, without using Expand.
func (r *Regexp) ReplaceAllLiteral(src, repl []byte) []byte {
matches, err := r.match(src, 0, true)
if err != nil {
panic(err)
}
if len(matches) == 0 {
return nil
}
out := make([]byte, len(src))
copy(out, src)
var diff int64
for _, match := range matches {
diff, out = replaceBytes(out, repl, match[0], match[1], diff)
}
return out
}
// ReplaceAllString is the String version of ReplaceAll
func (r *Regexp) ReplaceAllString(src, repl string) string {
return string(r.ReplaceAll([]byte(src), []byte(repl)))
}
// ReplaceAllStringFunc is the String version of ReplaceAllFunc
func (r *Regexp) ReplaceAllStringFunc(src string, repl func(string) string) string {
return string(r.ReplaceAllFunc([]byte(src), func(b []byte) []byte {
return []byte(repl(string(b)))
}))
}
// ReplaceAllLiteralString is the String version of ReplaceAllLiteral
func (r *Regexp) ReplaceAllLiteralString(src, repl string) string {
return string(r.ReplaceAllLiteral([]byte(src), []byte(repl)))
}
// Split slices s into substrings separated by the
// expression and returns a slice of the substrings
// between those expression matches.
//
// Example:
// s := regexp.MustCompile("a*").Split("abaabaccadaaae", 5)
// // s: ["", "b", "b", "c", "cadaaae"]
// The count determines the number of substrings to return:
// n > 0: at most n substrings; the last substring will be the unsplit remainder.
// n == 0: the result is nil (zero substrings)
// n < 0: all substrings
func (r *Regexp) Split(s string, n int) []string {
if n == 0 {
return nil
}
if len(r.expr) > 0 && len(s) == 0 {
return []string{""}
}
matches := r.FindAllStringIndex(s, n)
strings := make([]string, 0, len(matches))
beg := 0
end := 0
for _, match := range matches {
if n > 0 && len(strings) >= n-1 {
break
}
end = match[0]
if match[1] != 0 {
strings = append(strings, s[beg:end])
}
beg = match[1]
}
if end != len(s) {
strings = append(strings, s[beg:])
}
return strings
}
// String returns the text of the regular expression
// used for compilation.
func (r *Regexp) String() string {
return r.expr
}
// SubexpIndex returns the index of the subexpression
// with the given name, or -1 if there is no subexpression
// with that name.
func (r *Regexp) SubexpIndex(name string) int {
r.mtx.Lock()
defer r.mtx.Unlock()
// Get C string of name
cName, err := libc.CString(name)
if err != nil {
panic(err)
}
// Get substring index from name
ret := lib.Xpcre2_substring_number_from_name_8(r.tls, r.re, cName)
// If no substring error returned, return -1.
// If a different error is returned, panic.
if ret == lib.DPCRE2_ERROR_NOSUBSTRING {
return -1
} else if ret < 0 {
panic(codeToError(r.tls, ret))
}
// Return the index of the subexpression
return int(ret)
}
// replaceBytes replaces the bytes at a given location, and returns a new
// offset, based on how much bigger or smaller the slice got after replacement
func replaceBytes(src, repl []byte, sOff, eOff lib.Tsize_t, diff int64) (int64, []byte) {
var out []byte
out = append(
src[:int64(sOff)+diff],
append(
repl,
src[int64(eOff)+diff:]...,
)...,
)
return diff + int64(len(out)-len(src)), out
}
// match calls the underlying pcre match functions. It re-runs the functions
// until no matches are found if multi is set to true.
func (r *Regexp) match(b []byte, options uint32, multi bool) ([][]lib.Tsize_t, error) {
r.mtx.Lock()
defer r.mtx.Unlock()
// Create a C pointer to the subject
sp := unsafe.Pointer(&b[0])
cSubject := uintptr(sp)
// Convert the size of the subject to a C size_t type
cSubjectLen := lib.Tsize_t(len(b))
// Create match data using the pattern to figure out the buffer size
md := lib.Xpcre2_match_data_create_from_pattern_8(r.tls, r.re, 0)
if md == 0 {
panic("error creating match data")
}
// Free the match data at the end of the function
defer lib.Xpcre2_match_data_free_8(r.tls, md)
var offset lib.Tsize_t
var out [][]lib.Tsize_t
// While the offset is less than the length of the subject
for offset < cSubjectLen {
// Execute expression on subject
ret := lib.Xpcre2_match_8(r.tls, r.re, cSubject, cSubjectLen, offset, options, md, 0)
if ret < 0 {
// If no match found, break
if ret == lib.DPCRE2_ERROR_NOMATCH {
break
}
return nil, codeToError(r.tls, ret)
} else {
// Get amount of pairs in output vector
pairAmt := lib.Xpcre2_get_ovector_count_8(r.tls, md)
// Get pointer to output vector
ovec := lib.Xpcre2_get_ovector_pointer_8(r.tls, md)
// Create a Go slice using the output vector as the underlying array
slice := unsafe.Slice((*lib.Tsize_t)(unsafe.Pointer(ovec)), pairAmt*2)
// Create a new slice and copy the elements from the slice
// This is required because the match data will be freed in
// a defer, and that would cause a panic every time the slice
// is used later.
matches := make([]lib.Tsize_t, len(slice))
copy(matches, slice)
// If the two indices are the same (empty string), and the match is not
// immediately after another match, add it to the output and increment the
// offset. Otherwise, increment the offset and ignore the match.
if slice[0] == slice[1] && len(out) > 0 && slice[0] != out[len(out)-1][1] {
out = append(out, matches)
offset = slice[1] + 1
continue
} else if slice[0] == slice[1] {
offset = slice[1] + 1
continue
}
// Add the match to the output
out = append(out, matches)
// Set the next offset to the end index of the match
offset = matches[1]
}
// If multiple matches disabled, break
if !multi {
break
}
}
return out, nil
}
// patternInfo calls the underlying pcre pattern info function
// and returns information about the compiled regular expression
func (r *Regexp) patternInfo(what uint32) (out uint32) {
// Create a C pointer to the output integer
cOut := uintptr(unsafe.Pointer(&out))
// Get information about the compiled pattern
lib.Xpcre2_pattern_info_8(r.tls, r.re, what, cOut)
return
}
// Close frees resources used by the regular expression.
func (r *Regexp) Close() error {
if r == nil {
return nil
}
// Close thread-local storage
defer r.tls.Close()
// Free the compiled code
lib.Xpcre2_code_free_8(r.tls, r.re)
// Set regular expression to null
r.re = 0
return nil
}

236
pcre_test.go Normal file
View File

@ -0,0 +1,236 @@
package pcre_test
import (
"strings"
"sync"
"testing"
"go.arsenm.dev/pcre"
)
func TestCompileError(t *testing.T) {
r, err := pcre.Compile("(")
if err == nil {
t.Error("expected error, got nil")
}
defer r.Close()
}
func TestMatch(t *testing.T) {
r := pcre.MustCompile(`\d+ (?=USD)`)
defer r.Close()
matches := r.MatchString("9000 USD")
if !matches {
t.Error("expected 9000 USD to match")
}
matches = r.MatchString("9000 RUB")
if matches {
t.Error("expected 9000 RUB not to match")
}
matches = r.MatchString("800 USD")
if !matches {
t.Error("expected 800 USD to match")
}
matches = r.MatchString("700 CAD")
if matches {
t.Error("expected 700 CAD not to match")
}
matches = r.Match([]byte("8 USD"))
if !matches {
t.Error("expected 8 USD to match")
}
}
func TestMatchUngreedy(t *testing.T) {
r := pcre.MustCompileOpts(`Hello, (.+)\.`, pcre.Ungreedy)
defer r.Close()
submatches := r.FindAllStringSubmatch("Hello, World. Hello, pcre2.", 1)
if submatches[0][1] != "World" {
t.Errorf("expected World, got %s", submatches[0][1])
}
matches := r.MatchString("hello, world.")
if matches {
t.Error("expected lowercase 'hello, world' not to match")
}
}
func TestReplace(t *testing.T) {
r := pcre.MustCompile(`(\d+)\.\d+`)
defer r.Close()
testStr := "123.54321 Test"
newStr := r.ReplaceAllString(testStr, "${1}.12345")
if newStr != "123.12345 Test" {
t.Errorf(`expected "123.12345 Test", got "%s"`, newStr)
}
newStr = r.ReplaceAllString(testStr, "${9}.12345")
if newStr != ".12345 Test" {
t.Errorf(`expected ".12345 Test", got "%s"`, newStr)
}
newStr = r.ReplaceAllString(testStr, "${hi}.12345")
if newStr != ".12345 Test" {
t.Errorf(`expected ".12345 Test", got "%s"`, newStr)
}
newStr = r.ReplaceAllLiteralString(testStr, "${1}.12345")
if newStr != "${1}.12345 Test" {
t.Errorf(`expected "${1}.12345 Test", got "%s"`, newStr)
}
newStr = r.ReplaceAllStringFunc(testStr, func(s string) string {
return strings.Replace(s, ".", ",", -1)
})
if newStr != "123,54321 Test" {
t.Errorf(`expected "123,54321 Test", got "%s"`, newStr)
}
}
func TestSplit(t *testing.T) {
r := pcre.MustCompile("a*")
defer r.Close()
split := r.Split("abaabaccadaaae", 5)
expected := [5]string{"", "b", "b", "c", "cadaaae"}
if *(*[5]string)(split) != expected {
t.Errorf("expected %v, got %v", expected, split)
}
split = r.Split("", 0)
if split != nil {
t.Errorf("expected nil, got %v", split)
}
split = r.Split("", 5)
if split[0] != "" {
t.Errorf(`expected []string{""}, got %v`, split)
}
}
func TestFind(t *testing.T) {
r := pcre.MustCompile(`(\d+)`)
defer r.Close()
testStr := "3 times 4 is 12"
matches := r.FindAllString(testStr, -1)
if len(matches) != 3 {
t.Errorf("expected length 3, got %d", len(matches))
}
matches = r.FindAllString(testStr, 2)
if len(matches) != 2 {
t.Errorf("expected length 2, got %d", len(matches))
}
if matches[0] != "3" || matches[1] != "4" {
t.Errorf("expected [3 4], got %v", matches)
}
index := r.FindStringIndex(testStr)
if index[0] != 0 || index[1] != 1 {
t.Errorf("expected [0 1], got %v", index)
}
submatch := r.FindStringSubmatch(testStr)
if submatch[0] != "3" {
t.Errorf("expected 3, got %s", submatch[0])
}
index = r.FindStringSubmatchIndex(testStr)
if *(*[4]int)(index) != [4]int{0, 1, 0, 1} {
t.Errorf("expected [0 1 0 1], got %v", index)
}
submatches := r.FindAllStringSubmatchIndex(testStr, 2)
if len(submatches) != 2 {
t.Errorf("expected length 2, got %d", len(submatches))
}
expected := [2][4]int{{0, 1, 0, 1}, {8, 9, 8, 9}}
if *(*[4]int)(submatches[0]) != expected[0] {
t.Errorf("expected %v, got %v", expected[0], submatches[0])
}
if *(*[4]int)(submatches[1]) != expected[1] {
t.Errorf("expected %v, got %v", expected[0], submatches[0])
}
}
func TestSubexpIndex(t *testing.T) {
r := pcre.MustCompile(`(?P<number>\d)`)
defer r.Close()
index := r.SubexpIndex("number")
if index != 1 {
t.Errorf("expected 1, got %d", index)
}
index = r.SubexpIndex("string")
if index != -1 {
t.Errorf("expected -1, got %d", index)
}
num := r.NumSubexp()
if num != 1 {
t.Errorf("expected 1, got %d", num)
}
}
func TestConcurrency(t *testing.T) {
r := pcre.MustCompile(`\d*`)
defer r.Close()
wg := &sync.WaitGroup{}
wg.Add(1)
go func() {
defer wg.Done()
found := r.FindString("Test string 12345")
if found != "12345" {
t.Errorf("expected 12345, got %s", found)
}
}()
wg.Add(1)
go func() {
defer wg.Done()
matched := r.MatchString("Hello")
if matched {
t.Errorf("Expected Hello not to match")
}
}()
wg.Add(1)
go func() {
defer wg.Done()
matched := r.MatchString("54321")
if !matched {
t.Errorf("expected 54321 to match")
}
}()
wg.Wait()
}
func TestString(t *testing.T) {
const expr = `()`
r := pcre.MustCompile(expr)
defer r.Close()
if r.String() != expr {
t.Errorf("expected %s, got %s", expr, r.String())
}
}

38
types.go Normal file
View File

@ -0,0 +1,38 @@
package pcre
import "go.arsenm.dev/pcre/lib"
type CompileOption uint32
// Compile option bits
const (
Anchored = CompileOption(lib.DPCRE2_ANCHORED)
AllowEmptyClass = CompileOption(lib.DPCRE2_ALLOW_EMPTY_CLASS)
AltBsux = CompileOption(lib.DPCRE2_ALT_BSUX)
AltCircumflex = CompileOption(lib.DPCRE2_ALT_CIRCUMFLEX)
AltVerbnames = CompileOption(lib.DPCRE2_ALT_VERBNAMES)
AutoCallout = CompileOption(lib.DPCRE2_AUTO_CALLOUT)
Caseless = CompileOption(lib.DPCRE2_CASELESS)
DollarEndOnly = CompileOption(lib.DPCRE2_DOLLAR_ENDONLY)
DotAll = CompileOption(lib.DPCRE2_DOTALL)
DupNames = CompileOption(lib.DPCRE2_DUPNAMES)
EndAnchored = CompileOption(lib.DPCRE2_ENDANCHORED)
Extended = CompileOption(lib.DPCRE2_EXTENDED)
FirstLine = CompileOption(lib.DPCRE2_FIRSTLINE)
Literal = CompileOption(lib.DPCRE2_LITERAL)
MatchInvalidUTF = CompileOption(lib.DPCRE2_MATCH_INVALID_UTF)
MactchUnsetBackref = CompileOption(lib.DPCRE2_MATCH_UNSET_BACKREF)
Multiline = CompileOption(lib.DPCRE2_MULTILINE)
NeverBackslashC = CompileOption(lib.DPCRE2_NEVER_BACKSLASH_C)
NeverUCP = CompileOption(lib.DPCRE2_NEVER_UCP)
NeverUTF = CompileOption(lib.DPCRE2_NEVER_UTF)
NoAutoCapture = CompileOption(lib.DPCRE2_NO_AUTO_CAPTURE)
NoAutoPossess = CompileOption(lib.DPCRE2_NO_AUTO_POSSESS)
NoDotStarAnchor = CompileOption(lib.DPCRE2_NO_DOTSTAR_ANCHOR)
NoStartOptimize = CompileOption(lib.DPCRE2_NO_START_OPTIMIZE)
NoUTFCheck = CompileOption(lib.DPCRE2_NO_UTF_CHECK)
UCP = CompileOption(lib.DPCRE2_UCP)
Ungreedy = CompileOption(lib.DPCRE2_UNGREEDY)
UseOffsetLimit = CompileOption(lib.DPCRE2_USE_OFFSET_LIMIT)
UTF = CompileOption(lib.DPCRE2_UTF)
)