package ph7 /* #include "cgo.h" #include "ph7.h" */ import "C" import ( "fmt" "io" "unsafe" pointer "github.com/mattn/go-pointer" ) type ResultCode int const ( ResultCodeOK = ResultCode(C.PH7_OK) ResultCodeNoMem = ResultCode(C.PH7_NOMEM) ResultCodeAbort = ResultCode(C.PH7_ABORT) ResultCodeIOErr = ResultCode(C.PH7_IO_ERR) ResultCodeLooked = ResultCode(C.PH7_LOOKED) ResultCodeCorrupt = ResultCode(C.PH7_CORRUPT) ResultCodeCompileErr = ResultCode(C.PH7_COMPILE_ERR) ResultCodeVMErr = ResultCode(C.PH7_VM_ERR) ) func (r ResultCode) String() string { switch r { case ResultCodeOK: return "PH7_OK" case ResultCodeNoMem: return "PH7_NOMEM" case ResultCodeAbort: return "PH7_ABORT" case ResultCodeIOErr: return "PH7_IO_ERR" case ResultCodeLooked: return "PH7_LOOKED" case ResultCodeCorrupt: return "PH7_CORRUPT" case ResultCodeCompileErr: return "PH7_COMPILE_ERR" case ResultCodeVMErr: return "PH7_VM_ERR" default: return "UNKNOWN" } } type Error struct { Code ResultCode } func newError(code C.int) error { if code != C.PH7_OK { return Error{ Code: ResultCode(code), } } return nil } func (e Error) Error() string { return fmt.Sprintf("ph7: %s", e.Code) } type Engine struct { ptr *C.ph7 } func NewEngine() (Engine, error) { var engine Engine result := C.ph7_init(&engine.ptr) if result != C.PH7_OK { return Engine{}, newError(result) } return engine, nil } func (e Engine) ErrLog() (string, error) { var s *C.char var n C.int err := newError(C.engine_config_err_log(e.ptr, &s, &n)) if err != nil { return "", err } return C.GoStringN(s, n), nil } func (e Engine) Compile(source []byte, phpOnly bool) (*VM, error) { csource := C.CBytes(source) defer C.free(csource) var flags C.int if phpOnly { flags |= C.PH7_PHP_ONLY } var ptr *C.ph7_vm err := newError(C.ph7_compile_v2(e.ptr, (*C.char)(csource), C.int(len(source)), &ptr, flags)) if err != nil { return nil, err } return newVM(ptr), nil } func (e Engine) Close() error { return newError(C.ph7_release(e.ptr)) } type VM struct { ptr *C.ph7_vm pointerKey unsafe.Pointer outputWriter io.Writer // TODO clear outputWriteError when resetting VM outputWriteErr error } func newVM(cvm *C.ph7_vm) *VM { vm := new(VM) vm.ptr = cvm vm.pointerKey = pointer.Save(vm) return vm } //export write_vm_output func write_vm_output(buf unsafe.Pointer, bufLen C.uint, userData unsafe.Pointer) C.int { vm := pointer.Restore(userData).(*VM) gobuf := C.GoBytes(buf, C.int(bufLen)) _, vm.outputWriteErr = vm.outputWriter.Write(gobuf) if vm.outputWriteErr != nil { return C.int(ResultCodeAbort) } return C.int(ResultCodeOK) } func (vm *VM) SetOutputWriter(w io.Writer) error { vm.outputWriter = w return newError(C.vm_set_output_callback(vm.ptr, vm.pointerKey)) } func (vm *VM) OutputWriteError() error { return vm.outputWriteErr } func (vm *VM) ExtractOutput() (string, error) { var s *C.char var n C.int err := newError(C.vm_extract_output(vm.ptr, &s, &n)) if err != nil { return "", err } return C.GoStringN(s, n), nil } func (vm *VM) Exec() error { return newError(C.ph7_vm_exec(vm.ptr, (*C.int)(nil))) } func (vm *VM) Close() error { pointer.Unref(vm.pointerKey) return newError(C.ph7_vm_release(vm.ptr)) }