github.com/shadialtarsha/go-pcre@v0.0.0-20220904164957-b4f1834ceecc/pcre.go (about) 1 // Package pcre is a library that provides pcre2 regular expressions 2 // in pure Go, allowing for features such as cross-compiling. 3 // 4 // The lib directory contains source code automatically translated from 5 // pcre2's C source code for each supported architecture and/or OS. 6 // This package wraps the automatically-translated source to provide a 7 // safe interface as close to Go's regexp library as possible. 8 package pcre 9 10 import ( 11 "runtime" 12 "sync" 13 14 "github.com/shadialtarsha/go-pcre/lib" 15 16 "modernc.org/libc" 17 ) 18 19 // Version returns the version of pcre2 embedded in this library. 20 func Version() string { return lib.DPACKAGE_VERSION } 21 22 // Regexp represents a pcre2 regular expression 23 type Regexp struct { 24 mtx *sync.Mutex 25 expr string 26 re uintptr 27 tls *libc.TLS 28 } 29 30 // Compile runs CompileOpts with no options. 31 // 32 // Close() should be called on the returned expression 33 // once it is no longer needed. 34 func Compile(pattern string) (*Regexp, error) { 35 return CompileOpts(pattern, 0) 36 } 37 38 // CompileOpts compiles the provided pattern using the given options. 39 // 40 // Close() should be called on the returned expression 41 // once it is no longer needed. 42 func CompileOpts(pattern string, options CompileOption) (*Regexp, error) { 43 tls := libc.NewTLS() 44 45 // Get C string of pattern 46 cPattern, err := libc.CString(pattern) 47 if err != nil { 48 return nil, err 49 } 50 // Free the string when done 51 defer libc.Xfree(tls, cPattern) 52 53 // Allocate new error 54 cErr := allocError(tls) 55 // Free error when done 56 defer libc.Xfree(tls, cErr) 57 58 // Get error offsets 59 errPtr := addErrCodeOffset(cErr) 60 errOffsetPtr := addErrOffsetOffset(cErr) 61 62 // Convert pattern length to size_t type 63 cPatLen := lib.Tsize_t(len(pattern)) 64 65 // Compile expression 66 r := lib.Xpcre2_compile_8(tls, cPattern, cPatLen, uint32(options), errPtr, errOffsetPtr, 0) 67 if r == 0 { 68 return nil, ptrToError(tls, cErr) 69 } 70 71 // Create regexp instance 72 regex := Regexp{ 73 expr: pattern, 74 mtx: &sync.Mutex{}, 75 re: r, 76 tls: tls, 77 } 78 79 // Make sure resources are freed if GC collects the 80 // regular expression. 81 runtime.SetFinalizer(®ex, func(r *Regexp) error { 82 return r.Close() 83 }) 84 85 return ®ex, nil 86 } 87 88 // MustCompile compiles the given pattern and panics 89 // if there was an error 90 // 91 // Close() should be called on the returned expression 92 // once it is no longer needed. 93 func MustCompile(pattern string) *Regexp { 94 rgx, err := Compile(pattern) 95 if err != nil { 96 panic(err) 97 } 98 return rgx 99 } 100 101 // MustCompileOpts compiles the given pattern with the given 102 // options and panics if there was an error. 103 // 104 // Close() should be called on the returned expression 105 // once it is no longer needed. 106 func MustCompileOpts(pattern string, options CompileOption) *Regexp { 107 rgx, err := CompileOpts(pattern, options) 108 if err != nil { 109 panic(err) 110 } 111 return rgx 112 } 113 114 // Close frees resources used by the regular expression. 115 func (r *Regexp) Close() error { 116 if r == nil { 117 return nil 118 } 119 120 // Close thread-local storage 121 defer r.tls.Close() 122 123 // Free the compiled code 124 lib.Xpcre2_code_free_8(r.tls, r.re) 125 // Set regular expression to null 126 r.re = 0 127 128 return nil 129 }