diff --git a/glob.go b/glob.go new file mode 100644 index 0000000..b0bd7da --- /dev/null +++ b/glob.go @@ -0,0 +1,58 @@ +package pcre + +import ( + "unsafe" + + "go.arsenm.dev/pcre/lib" + "modernc.org/libc" +) + +// CompileGlob converts the given glob into a +// pcre regular expression, and then compiles it, +// returning the result. +func CompileGlob(glob string) (*Regexp, error) { + tls := libc.NewTLS() + defer tls.Close() + + // Get C string from given glob + cGlob, err := libc.CString(glob) + if err != nil { + return nil, err + } + defer libc.Xfree(tls, cGlob) + // Convert length to size_t + cGlobLen := lib.Tsize_t(len(glob)) + + // Create null pointer + outPtr := uintptr(0) + // Get pointer to pointer + cOutPtr := uintptr(unsafe.Pointer(&outPtr)) + + // Create 0 size_t + outLen := lib.Tsize_t(0) + // Get pointer to size_t + cOutLen := uintptr(unsafe.Pointer(&outLen)) + + // Convert glob to regular expression + ret := lib.Xpcre2_pattern_convert_8( + tls, + cGlob, + cGlobLen, + lib.DPCRE2_CONVERT_GLOB, + cOutPtr, + cOutLen, + 0, + ) + if ret != 0 { + return nil, codeToError(tls, ret) + } + + // Get output as byte slice + out := unsafe.Slice((*byte)(unsafe.Pointer(outPtr)), outLen) + // Convert output to string + // This copies the data, so it's safe for later use + pattern := string(out) + + // Compile converted glob and return results + return Compile(pattern) +} diff --git a/glob_test.go b/glob_test.go new file mode 100644 index 0000000..3d0f0b9 --- /dev/null +++ b/glob_test.go @@ -0,0 +1,38 @@ +package pcre_test + +import ( + "testing" + + "go.arsenm.dev/pcre" +) + +func TestCompileGlob(t *testing.T) { + r, err := pcre.CompileGlob("/**/bin") + if err != nil { + t.Fatal(err) + } + + if !r.MatchString("/bin") { + t.Error("expected /bin to match") + } + + if !r.MatchString("/usr/bin") { + t.Error("expected /usr/bin to match") + } + + if !r.MatchString("/usr/local/bin") { + t.Error("expected /usr/local/bin to match") + } + + if r.MatchString("/usr") { + t.Error("expected /usr not to match") + } + + if r.MatchString("/usr/local") { + t.Error("expected /usr/local not to match") + } + + if r.MatchString("/home") { + t.Error("expected /home not to match") + } +}