github.com/shadialtarsha/go-pcre@v0.0.0-20220904164957-b4f1834ceecc/error.go (about)

     1  package pcre
     2  
     3  import (
     4  	"fmt"
     5  	"unsafe"
     6  
     7  	"github.com/shadialtarsha/go-pcre/lib"
     8  
     9  	"modernc.org/libc"
    10  	"modernc.org/libc/sys/types"
    11  )
    12  
    13  var pce pcreError
    14  
    15  // pcreError is meant to be manually allocated
    16  // for when pcre requires a pointer to store an error
    17  // such as for Xpcre2_compile_8().
    18  type pcreError struct {
    19  	errCode   int32
    20  	errOffset lib.Tsize_t
    21  }
    22  
    23  // allocError manually allocates memory for the
    24  // pcreError struct.
    25  //
    26  // libc.Xfree() should be called on the returned
    27  // pointer once it is no longer needed.
    28  func allocError(tls *libc.TLS) uintptr {
    29  	return libc.Xmalloc(tls, types.Size_t(unsafe.Sizeof(pce)))
    30  }
    31  
    32  // addErrCodeOffset adds the offset of the error code
    33  // within the pcreError struct to a given pointer
    34  func addErrCodeOffset(p uintptr) uintptr {
    35  	ptrOffset := unsafe.Offsetof(pce.errCode)
    36  	return p + ptrOffset
    37  }
    38  
    39  // addErrOffsetOffset adds the offset of the error
    40  // offset within the pcreError struct to a given pointer
    41  func addErrOffsetOffset(p uintptr) uintptr {
    42  	offsetOffset := unsafe.Offsetof(pce.errOffset)
    43  	return p + offsetOffset
    44  }
    45  
    46  // ptrToError converts the given pointer to a Go error
    47  func ptrToError(tls *libc.TLS, pe uintptr) *PcreError {
    48  	eo := *(*pcreError)(unsafe.Pointer(pe))
    49  
    50  	err := codeToError(tls, eo.errCode)
    51  	err.offset = eo.errOffset
    52  	err.hasOffset = true
    53  
    54  	return err
    55  }
    56  
    57  // codeToError converts the given error code into a Go error
    58  func codeToError(tls *libc.TLS, code int32) *PcreError {
    59  	errBuf := make([]byte, 256)
    60  	cErrBuf := uintptr(unsafe.Pointer(&errBuf[0]))
    61  
    62  	// Get the textual error message associated with the code,
    63  	// and store it in errBuf.
    64  	msgLen := lib.Xpcre2_get_error_message_8(tls, code, cErrBuf, 256)
    65  
    66  	return &PcreError{false, 0, string(errBuf[:msgLen])}
    67  }
    68  
    69  // PcreError represents errors returned
    70  // by underlying pcre2 functions.
    71  type PcreError struct {
    72  	hasOffset bool
    73  	offset    lib.Tsize_t
    74  	errStr    string
    75  }
    76  
    77  // Error returns the string within the error,
    78  // prepending the offset if it exists.
    79  func (pe *PcreError) Error() string {
    80  	if !pe.hasOffset {
    81  		return pe.errStr
    82  	}
    83  	return fmt.Sprintf("offset %d: %s", pe.offset, pe.errStr)
    84  }