-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcgoutil.go
102 lines (86 loc) · 2.35 KB
/
cgoutil.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package cgoutil
/*
#include <stdlib.h>
#include <stdio.h>
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 {
Length int
Pointer unsafe.Pointer
}
// 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))
}