85 lines
2.0 KiB

package pcre
import (
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
err.hasOffset = true
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{false, 0, string(errBuf[:msgLen])}
// PcreError represents errors returned
// by underlying pcre2 functions.
type PcreError struct {
hasOffset bool
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.hasOffset {
return pe.errStr
return fmt.Sprintf("offset %d: %s", pe.offset, pe.errStr)