package raygui /* #include // Code from https://blog.pytool.com/language/golang/cgo/go-cgo-string/ static char** make_str_array(int size) { return calloc(sizeof(char*), size); } static int len_str_array(char **arr) { int i = 0; while (arr[i] != NULL) i++; return i+1; // NULL does count } static void set_str_array(char **arr, int idx, char *s) { arr[idx] = s; } static void free_str_array(char **arr, int size) { int i; for (i = 0; i < size; i++) { free(arr[i]); } free(arr); } */ import "C" import ( "unsafe" ) // CStringArray represents an array of pointers to NULL terminated C strings, // the array itself is terminated with a NULL type CStringArray struct { Pointer unsafe.Pointer Length int } // NewCStringArray returns an instance of CStringArray func NewCStringArray() *CStringArray { return &CStringArray{} } // NewCStringArrayFromSlice makes an instance of CStringArray then copy the // input slice to it. func NewCStringArrayFromSlice(ss []string) *CStringArray { var arr CStringArray arr.Copy(ss) return &arr } func NewCStringArrayFromPointer(p unsafe.Pointer) *CStringArray { return &CStringArray{ Length: int(C.len_str_array((**C.char)(p))), Pointer: p, } } // ToSlice converts CStringArray to Go slice of strings func (arr *CStringArray) ToSlice() []string { if arr.Length == 0 || arr.Pointer == nil { return []string{} } var ss []string var cs **C.char defer C.free(unsafe.Pointer(cs)) p := uintptr(arr.Pointer) for { cs = *(***C.char)(unsafe.Pointer(&p)) if *cs == nil { // skip NULL - the last element break } ss = append(ss, C.GoString(*cs)) p += unsafe.Sizeof(p) } return ss } // Copy converts Go slice of strings to C underlying struct of CStringArray func (arr *CStringArray) Copy(ss []string) { arr.Length = len(ss) + 1 // one more element for NULL at the end arr.Pointer = unsafe.Pointer(C.make_str_array(C.int(arr.Length))) for i, s := range ss { cs := C.CString(s) // will be free by Free() method C.set_str_array((**C.char)(arr.Pointer), C.int(i), cs) } } // Free frees C underlying struct of CStringArray // MUST call this method after using CStringArray // Exception: If you use NewCStringArrayFromPointer() to create CStringArray object // and you use other way to free C underlying structure pointed by the pointer, // then don't need to call Free() func (arr *CStringArray) Free() { C.free_str_array((**C.char)(arr.Pointer), C.int(arr.Length)) }