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 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) }