diff --git a/README.md b/README.md deleted file mode 100644 index 7bb638f..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# go-ncurses - diff --git a/examples/basic.go b/examples/basic.go new file mode 100644 index 0000000..5e438d5 --- /dev/null +++ b/examples/basic.go @@ -0,0 +1,23 @@ +package main + +import ( + "fmt" + + "git.metznet.ca/MetzNet/go-ncurses" +) + +func main() { + err := ncurses.Init() + if err != nil { + panic(err) + } + + window := ncurses.InitScr.Load()() + + x := ncurses.GetMaxX.Load()(window) + y := ncurses.GetMaxY.Load()(window) + + fmt.Printf("%d x %d\n", x, y) + + ncurses.EndWin.Load()() +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..9569e29 --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module git.metznet.ca/MetzNet/go-ncurses + +go 1.22.2 + +require ( + github.com/ebitengine/purego v0.7.1 // indirect + golang.org/x/sys v0.7.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..85ace07 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/ebitengine/purego v0.7.1 h1:6/55d26lG3o9VCZX8lping+bZcmShseiqlh2bnUDiPA= +github.com/ebitengine/purego v0.7.1/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/ncurses.go b/ncurses.go new file mode 100644 index 0000000..c4889be --- /dev/null +++ b/ncurses.go @@ -0,0 +1,79 @@ +package ncurses + +import ( + "fmt" + "sync/atomic" + + "github.com/ebitengine/purego" +) + +var ncurses atomic.Value + +func Init() error { + if ncurses.Load() == nil { + lib, err := purego.Dlopen(LIBRARY_PATH, purego.RTLD_GLOBAL | purego.RTLD_LAZY) + if err != nil { + return err + } + ncurses.CompareAndSwap(nil, lib) + } + + return nil +} + +type loaded_function[T any] struct { + name string + value atomic.Value + library *atomic.Value +} + +func NewLoadedFunction[T any](library *atomic.Value, name string) loaded_function[T] { + return loaded_function[T]{ + name: name, + value: atomic.Value{}, + library: library, + } +} + +func(f *loaded_function[T]) Load() T { + if f.library.Load() == nil { + panic(fmt.Sprintf("Attempted to call library function %s before loading library", f.name)) + } else if f.value.Load() == nil { + var tmp T + purego.RegisterLibFunc(&tmp, f.library.Load().(uintptr), f.name) + f.value.CompareAndSwap(nil, tmp) + } + return f.value.Load().(T) +} + +type Window uintptr + +type voidFP func() int +type winFP func(window Window) int + +type initscrFP func() Window +var InitScr = NewLoadedFunction[initscrFP](&ncurses, "initscr") +var EndWin = NewLoadedFunction[voidFP](&ncurses, "endwin") + +type newwinFP func(nlines, ncols, begin_x, begin_y int) Window +var NewWin = NewLoadedFunction[newwinFP](&ncurses, "newwin") +var DelWin = NewLoadedFunction[winFP](&ncurses, "delwin") +type dupwinFP func(window Window) Window +var DupWin = NewLoadedFunction[dupwinFP](&ncurses, "dupwin") + +var Refresh = NewLoadedFunction[voidFP](&ncurses, "refresh") +var WRefresh = NewLoadedFunction[winFP](&ncurses, "wrefresh") +var WNOutRefresh = NewLoadedFunction[winFP](&ncurses, "wnoutrefresh") +var DoUpdate = NewLoadedFunction[voidFP](&ncurses, "doupdate") + +type waddstrFP func(window Window, str string) int +var WAddStr = NewLoadedFunction[waddstrFP](&ncurses, "waddstr") + +type waddnstrFP func(window Window, str string, n int) int +var WAddNStr = NewLoadedFunction[waddstrFP](&ncurses, "waddnstr") + +var GetMaxY = NewLoadedFunction[winFP](&ncurses, "getmaxy") +var GetMaxX = NewLoadedFunction[winFP](&ncurses, "getmaxx") + +type mvwaddstrFP func(window Window, x, y int, str string) int +var MvWAddStr = NewLoadedFunction[mvwaddstrFP](&ncurses, "mvwaddstr") diff --git a/ncurses_darwin.go b/ncurses_darwin.go new file mode 100644 index 0000000..ea15538 --- /dev/null +++ b/ncurses_darwin.go @@ -0,0 +1,3 @@ +package ncurses + +const LIBRARY_PATH = "libncurses.dylib" diff --git a/ncurses_test.go b/ncurses_test.go new file mode 100644 index 0000000..fa4ae75 --- /dev/null +++ b/ncurses_test.go @@ -0,0 +1,43 @@ +package ncurses + +import ( + "testing" +) + +func StartTest(t *testing.T) Window { + err := Init() + if err != nil { + t.Fatalf("Init err - %s", err) + } + + window := InitScr.Load()() + return window +} + +func EndTest(t *testing.T) { + ret := EndWin.Load()() + if ret != 0 { + t.Fatalf("EndWin result - 0x%x", ret) + } +} + +func TestInitScr(t *testing.T) { + window := StartTest(t) + t.Logf("InitScr result - 0x%x", window) + EndTest(t) +} + +func TestNewWin(t *testing.T) { + StartTest(t) + + window := NewWin.Load()(10, 10, 0, 0) + t.Logf("NewWin result - 0x%x", window) + + ret := DelWin.Load()(window) + if ret != 0 { + t.Fatalf("DelWin result - 0x%x", ret) + } + + EndTest(t) +} +