Mercurial > pub > dyncall > bindings
diff go/godc/godc.go @ 0:0cfcc391201f
initial from svn dyncall-1745
author | Daniel Adler |
---|---|
date | Thu, 19 Mar 2015 22:26:28 +0100 |
parents | |
children | 8a45a05ff64e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/go/godc/godc.go Thu Mar 19 22:26:28 2015 +0100 @@ -0,0 +1,282 @@ +/* + + godc.go + Copyright (c) 2014 Tassilo Philipp <tphilipp@potion-studios.com> + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +*/ + + +// Go/dyncall extension implementation. +package godc + +// #cgo LDFLAGS: -L../../../dyncall/ -ldyncall_s +// #cgo LDFLAGS: -L../../../dynload/ -ldynload_s +// #cgo LDFLAGS: -L../../../dyncallback/ -ldyncallback_s +// #include <stdlib.h> +// #include "../../../dyncall/dyncall/dyncall.h" +// #include "../../../dyncall/dynload/dynload.h" +// #include "../../../dyncall/dyncall/dyncall_signature.h" +import "C" +import ( + "unsafe" + "fmt" + "reflect" +) + +type ExtLib struct { + lib *C.DLLib + syms *C.DLSyms +} + +type CallVM struct { + cvm *C.DCCallVM +} + + +// dynload +func (p *ExtLib) Load(path string) error { + s := C.CString(path) + defer C.free(unsafe.Pointer(s)) + p.lib = C.dlLoadLibrary(s) + if p.lib != nil { return nil } + return fmt.Errorf("Can't load %s", path) +} + +func (p *ExtLib) Free() { + C.dlFreeLibrary(p.lib) +} + +func (p *ExtLib) FindSymbol(name string) unsafe.Pointer { + s := C.CString(name) + defer C.free(unsafe.Pointer(s)) + return unsafe.Pointer(C.dlFindSymbol(p.lib, s)) +} + + +// dynload Syms +func (p *ExtLib) SymsInit(path string) error { + s := C.CString(path) + defer C.free(unsafe.Pointer(s)) + p.syms = C.dlSymsInit(s) + if p.syms != nil { return nil } + return fmt.Errorf("Can't load %s", path) +} + +func (p *ExtLib) SymsCleanup() { + C.dlSymsCleanup(p.syms) +} + +func (p *ExtLib) SymsCount() int { + return int(C.dlSymsCount(p.syms)) +} + +func (p *ExtLib) SymsName(i int) string { + return C.GoString(C.dlSymsName(p.syms, C.int(i))) +} + +func (p *ExtLib) SymsNameFromValue(v unsafe.Pointer) string { + return C.GoString(C.dlSymsNameFromValue(p.syms, v)) +} + + +// dyncall +func (p *CallVM) InitCallVM() error { + return p.InitCallVMWithStackSize(4096) +} + +func (p *CallVM) InitCallVMWithStackSize(stackSize int) error { + p.cvm = C.dcNewCallVM(C.DCsize(stackSize)) + if p.cvm != nil { return nil } + return fmt.Errorf("Can't create CallVM") +} + +func (p *CallVM) Free() { + C.dcFree(p.cvm) +} + +func (p *CallVM) Reset() { + C.dcReset(p.cvm) +} + + + +// Modes +const ( + DC_CALL_C_DEFAULT = C.DC_CALL_C_DEFAULT + DC_CALL_C_ELLIPSIS = C.DC_CALL_C_ELLIPSIS + DC_CALL_C_ELLIPSIS_VARARGS = C.DC_CALL_C_ELLIPSIS_VARARGS + DC_CALL_C_X86_CDECL = C.DC_CALL_C_X86_CDECL + DC_CALL_C_X86_WIN32_STD = C.DC_CALL_C_X86_WIN32_STD + DC_CALL_C_X86_WIN32_FAST_MS = C.DC_CALL_C_X86_WIN32_FAST_MS + DC_CALL_C_X86_WIN32_FAST_GNU = C.DC_CALL_C_X86_WIN32_FAST_GNU + DC_CALL_C_X86_WIN32_THIS_MS = C.DC_CALL_C_X86_WIN32_THIS_MS + DC_CALL_C_X86_WIN32_THIS_GNU = C.DC_CALL_C_X86_WIN32_THIS_GNU + DC_CALL_C_X64_WIN64 = C.DC_CALL_C_X64_WIN64 + DC_CALL_C_X64_SYSV = C.DC_CALL_C_X64_SYSV + DC_CALL_C_PPC32_DARWIN = C.DC_CALL_C_PPC32_DARWIN + DC_CALL_C_PPC32_OSX = C.DC_CALL_C_PPC32_OSX + DC_CALL_C_ARM_ARM_EABI = C.DC_CALL_C_ARM_ARM_EABI + DC_CALL_C_ARM_THUMB_EABI = C.DC_CALL_C_ARM_THUMB_EABI + DC_CALL_C_ARM_ARMHF = C.DC_CALL_C_ARM_ARMHF + DC_CALL_C_MIPS32_EABI = C.DC_CALL_C_MIPS32_EABI + DC_CALL_C_MIPS32_PSPSDK = C.DC_CALL_C_MIPS32_PSPSDK + DC_CALL_C_PPC32_SYSV = C.DC_CALL_C_PPC32_SYSV + DC_CALL_C_PPC32_LINUX = C.DC_CALL_C_PPC32_LINUX + DC_CALL_C_ARM_ARM = C.DC_CALL_C_ARM_ARM + DC_CALL_C_ARM_THUMB = C.DC_CALL_C_ARM_THUMB + DC_CALL_C_MIPS32_O32 = C.DC_CALL_C_MIPS32_O32 + DC_CALL_C_MIPS64_N32 = C.DC_CALL_C_MIPS64_N32 + DC_CALL_C_MIPS64_N64 = C.DC_CALL_C_MIPS64_N64 + DC_CALL_C_X86_PLAN9 = C.DC_CALL_C_X86_PLAN9 + DC_CALL_C_SPARC32 = C.DC_CALL_C_SPARC32 + DC_CALL_C_SPARC64 = C.DC_CALL_C_SPARC64 + DC_CALL_SYS_DEFAULT = C.DC_CALL_SYS_DEFAULT + DC_CALL_SYS_X86_INT80H_LINUX = C.DC_CALL_SYS_X86_INT80H_LINUX + DC_CALL_SYS_X86_INT80H_BSD = C.DC_CALL_SYS_X86_INT80H_BSD +) + + +func (p *CallVM) Mode(mode int) { + C.dcMode(p.cvm, C.DCint(mode)) +} + +// Error codes +const ( + DC_ERROR_NONE = C.DC_ERROR_NONE + DC_ERROR_UNSUPPORTED_MODE = C.DC_ERROR_UNSUPPORTED_MODE +) + + +func (p *CallVM) GetError() int { + return int(C.dcGetError(p.cvm)) +} + + +// Helper for string/pointer conversion, needed as low-level string alloc needs to be freed in different scope +func (p *CallVM) AllocCString(value string) unsafe.Pointer { s := C.CString(value); return unsafe.Pointer(s) } +func (p *CallVM) FreeCString (value unsafe.Pointer) { C.free(value) } + +// Args +func (p *CallVM) ArgBool (value bool) { if value==true { C.dcArgBool(p.cvm, C.DC_TRUE) } else { C.dcArgBool(p.cvm, C.DC_FALSE) } } +func (p *CallVM) ArgChar (value int8) { C.dcArgChar (p.cvm, C.DCchar (value)) } +func (p *CallVM) ArgShort (value int16) { C.dcArgShort (p.cvm, C.DCshort (value)) } +func (p *CallVM) ArgInt (value int) { C.dcArgInt (p.cvm, C.DCint (value)) } +func (p *CallVM) ArgLong (value int32) { C.dcArgLong (p.cvm, C.DClong (value)) } +func (p *CallVM) ArgLongLong (value int64) { C.dcArgLongLong(p.cvm, C.DClonglong(value)) } +func (p *CallVM) ArgFloat (value float32) { C.dcArgFloat (p.cvm, C.DCfloat (value)) } +func (p *CallVM) ArgDouble (value float64) { C.dcArgDouble (p.cvm, C.DCdouble (value)) } +func (p *CallVM) ArgPointer (value unsafe.Pointer) { C.dcArgPointer (p.cvm, C.DCpointer (value)) } +//@@@func (p *CallVM) ArgStruct (s C.DCstruct*, value unsafe.Pointer) + +// "Formatted" args +// - first takes Go's types (as they cover all C types dyncall supports) and pushes values accordingly +// - second uses a dyncall signature for implicit type conversion/casting, however it uses reflect package and is slower +// Note that first version doesn't feature calling convention mode switching. +func (p *CallVM) ArgF_Go(args ...interface{}) error { + + for i, n := 0, len(args); i<n; i++ { + switch args[i].(type) { + case bool: p.ArgBool ( (args[i].(bool ))) + case int8: p.ArgChar ( (args[i].(int8 ))) + case uint8/*byte*/: p.ArgChar (int8 (args[i].(uint8 ))) + case int16: p.ArgShort ( (args[i].(int16 ))) + case uint16: p.ArgShort (int16 (args[i].(uint16 ))) + case int: p.ArgInt ( (args[i].(int ))) + case uint: p.ArgInt (int (args[i].(uint ))) + case int32/*rune*/: p.ArgLong ( (args[i].(int32 ))) + case uint32: p.ArgLong (int32 (args[i].(uint32 ))) + case int64: p.ArgLongLong( (args[i].(int64 ))) + case uint64: p.ArgLongLong(int64 (args[i].(uint64 ))) + case float32: p.ArgFloat ( (args[i].(float32 ))) + case float64: p.ArgDouble ( (args[i].(float64 ))) + case uintptr: p.ArgPointer (unsafe.Pointer(args[i].(unsafe.Pointer))) + case unsafe.Pointer: p.ArgPointer ( (args[i].(unsafe.Pointer))) + default: return fmt.Errorf("Unknown type passed to ArgF_Go") + } + } + return nil +} + +func (p *CallVM) ArgF(signature string, args ...interface{}) { + + tb := reflect.TypeOf((*bool )(nil)).Elem() + ti := reflect.TypeOf((*int64 )(nil)).Elem() + tf := reflect.TypeOf((*float64)(nil)).Elem() + tp := reflect.TypeOf((*uintptr)(nil)).Elem() + + for i, n := 0, len(signature); i<n; i++ { + //@@@ add support for calling convention mode(s) + switch s := signature[i]; s { + case C.DC_SIGCHAR_BOOL: p.ArgBool (bool (reflect.ValueOf(args[i]).Convert(tb).Bool ())) + case C.DC_SIGCHAR_CHAR, C.DC_SIGCHAR_UCHAR: p.ArgChar (int8 (reflect.ValueOf(args[i]).Convert(ti).Int ())) + case C.DC_SIGCHAR_INT, C.DC_SIGCHAR_UINT: p.ArgInt (int (reflect.ValueOf(args[i]).Convert(ti).Int ())) + case C.DC_SIGCHAR_LONG, C.DC_SIGCHAR_ULONG: p.ArgLong (int32 (reflect.ValueOf(args[i]).Convert(ti).Int ())) + case C.DC_SIGCHAR_LONGLONG, C.DC_SIGCHAR_ULONGLONG: p.ArgLongLong(int64 (reflect.ValueOf(args[i]).Convert(ti).Int ())) + case C.DC_SIGCHAR_FLOAT: p.ArgFloat (float32 (reflect.ValueOf(args[i]).Convert(tf).Float ())) + case C.DC_SIGCHAR_DOUBLE: p.ArgDouble (float64 (reflect.ValueOf(args[i]).Convert(tf).Float ())) + case C.DC_SIGCHAR_POINTER, C.DC_SIGCHAR_STRING: p.ArgPointer (unsafe.Pointer(reflect.ValueOf(args[i]).Convert(tp).Pointer())) + case C.DC_SIGCHAR_ENDARG: return + } + // Faster, but doesn't do cross-type conversions. + //switch s := signature[i]; s { + // case C.DC_SIGCHAR_BOOL: p.ArgBool (args[i].(bool )) + // case C.DC_SIGCHAR_CHAR, C.DC_SIGCHAR_UCHAR: p.ArgChar (args[i].(int8 )) + // case C.DC_SIGCHAR_SHORT, C.DC_SIGCHAR_USHORT: p.ArgShort (args[i].(int16 )) + // case C.DC_SIGCHAR_INT, C.DC_SIGCHAR_UINT: p.ArgInt (args[i].(int )) + // case C.DC_SIGCHAR_LONG, C.DC_SIGCHAR_ULONG: p.ArgLong (args[i].(int32 )) + // case C.DC_SIGCHAR_LONGLONG, C.DC_SIGCHAR_ULONGLONG: p.ArgLongLong(args[i].(int64 )) + // case C.DC_SIGCHAR_FLOAT: p.ArgFloat (args[i].(float32 )) + // case C.DC_SIGCHAR_DOUBLE: p.ArgDouble (args[i].(float64 )) + // case C.DC_SIGCHAR_POINTER, C.DC_SIGCHAR_STRING: p.ArgPointer (args[i].(unsafe.Pointer)) + // case C.DC_SIGCHAR_ENDARG: return + //} + } +} + + +// Calls +func (p *CallVM) CallVoid (funcptr unsafe.Pointer) { C.dcCallVoid (p.cvm, C.DCpointer(funcptr)) } +func (p *CallVM) CallBool (funcptr unsafe.Pointer) bool { b := (C.dcCallBool(p.cvm, C.DCpointer(funcptr))); if b==C.DC_TRUE { return true } else { return false } } +func (p *CallVM) CallChar (funcptr unsafe.Pointer) int8 { return int8 (C.dcCallChar (p.cvm, C.DCpointer(funcptr))) } +func (p *CallVM) CallShort (funcptr unsafe.Pointer) int16 { return int16 (C.dcCallShort (p.cvm, C.DCpointer(funcptr))) } +func (p *CallVM) CallInt (funcptr unsafe.Pointer) int { return int (C.dcCallInt (p.cvm, C.DCpointer(funcptr))) } +func (p *CallVM) CallLong (funcptr unsafe.Pointer) int32 { return int32 (C.dcCallLong (p.cvm, C.DCpointer(funcptr))) } +func (p *CallVM) CallLongLong (funcptr unsafe.Pointer) int64 { return int64 (C.dcCallLongLong(p.cvm, C.DCpointer(funcptr))) } +func (p *CallVM) CallFloat (funcptr unsafe.Pointer) float32 { return float32 (C.dcCallFloat (p.cvm, C.DCpointer(funcptr))) } +func (p *CallVM) CallDouble (funcptr unsafe.Pointer) float64 { return float64 (C.dcCallDouble (p.cvm, C.DCpointer(funcptr))) } +func (p *CallVM) CallPointer (funcptr unsafe.Pointer) unsafe.Pointer { return unsafe.Pointer(C.dcCallPointer (p.cvm, C.DCpointer(funcptr))) } +func (p *CallVM) CallPointerToStr(funcptr unsafe.Pointer) string { return C.GoString((*C.char)(C.dcCallPointer (p.cvm, C.DCpointer(funcptr)))) } // For convenience +//@@@func (p *CallVM) CallStruct (funcptr unsafe.Pointer, s C.DCstruct* s, returnValue unsafe.Pointer) + +// "Formatted" calls +//@@@func (p *CallVM) Call(result, funcptr unsafe.Pointer, signature string, args ...interface{}) { +//@@@... +//@@@} + + +//void dcCallF (DCCallVM* vm, DCValue* result, DCpointer funcptr, const DCsigchar* signature, ...); + +/* +DC_API DCstruct* dcNewStruct (DCsize fieldCount, DCint alignment); +DC_API void dcStructField (DCstruct* s, DCint type, DCint alignment, DCsize arrayLength); +DC_API void dcSubStruct (DCstruct* s, DCsize fieldCount, DCint alignment, DCsize arrayLength); +DC_API void dcCloseStruct (DCstruct* s); +DC_API DCsize dcStructSize (DCstruct* s); +DC_API DCsize dcStructAlignment(DCstruct* s); +DC_API void dcFreeStruct (DCstruct* s); + +DC_API DCstruct* dcDefineStruct (const char* signature); +*/ +