2023-10-27 09:20:02 +00:00
|
|
|
package hcl
|
|
|
|
|
|
|
|
/*
|
|
|
|
#include <hcl.h>
|
|
|
|
#include <hcl-utl.h>
|
|
|
|
*/
|
|
|
|
import "C"
|
|
|
|
|
|
|
|
import (
|
2023-10-31 12:17:08 +00:00
|
|
|
"bufio"
|
|
|
|
"io"
|
2023-10-27 09:20:02 +00:00
|
|
|
"os"
|
2023-11-05 14:33:22 +00:00
|
|
|
"path"
|
2023-10-31 12:17:08 +00:00
|
|
|
"sync"
|
|
|
|
"unsafe"
|
2023-10-27 09:20:02 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type IOHandle struct {
|
|
|
|
file *os.File
|
|
|
|
ioif interface{}
|
|
|
|
}
|
2023-10-29 17:30:19 +00:00
|
|
|
|
2023-10-27 09:20:02 +00:00
|
|
|
type IOHandleTable struct {
|
|
|
|
mtx sync.Mutex
|
|
|
|
handles []IOHandle
|
|
|
|
free_slots []int
|
|
|
|
}
|
|
|
|
|
|
|
|
func (io *IOHandleTable) add_io_handle(f *os.File, ioif interface{}) int {
|
|
|
|
io.mtx.Lock()
|
|
|
|
defer io.mtx.Unlock()
|
|
|
|
|
|
|
|
var n int = len(io.free_slots)
|
|
|
|
|
|
|
|
if n <= 0 { // no free slots
|
|
|
|
io.handles = append(io.handles, IOHandle{file: f, ioif: ioif})
|
|
|
|
return len(io.handles) - 1
|
|
|
|
} else {
|
|
|
|
var slot int
|
|
|
|
n--
|
|
|
|
slot = io.free_slots[n]
|
|
|
|
io.free_slots = io.free_slots[:n]
|
|
|
|
io.handles[slot].file = f
|
|
|
|
io.handles[slot].ioif = ioif
|
|
|
|
return slot
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (io *IOHandleTable) del_io_handle(slot int) IOHandle {
|
|
|
|
var (
|
|
|
|
h IOHandle
|
|
|
|
n int
|
|
|
|
)
|
|
|
|
|
|
|
|
io.mtx.Lock()
|
|
|
|
defer io.mtx.Unlock()
|
|
|
|
|
|
|
|
h = io.handles[slot]
|
|
|
|
io.handles[slot].file = nil
|
|
|
|
io.handles[slot].ioif = nil
|
|
|
|
|
|
|
|
n = len(io.handles)
|
|
|
|
if slot == n-1 {
|
|
|
|
io.handles = io.handles[:n-1]
|
|
|
|
} else {
|
|
|
|
io.free_slots = append(io.free_slots, slot)
|
|
|
|
}
|
|
|
|
|
|
|
|
return h
|
|
|
|
}
|
|
|
|
|
|
|
|
func (io *IOHandleTable) slot_to_io_handle(slot int) IOHandle {
|
|
|
|
io.mtx.Lock()
|
|
|
|
defer io.mtx.Unlock()
|
|
|
|
return io.handles[slot]
|
|
|
|
}
|
|
|
|
|
|
|
|
var io_tab IOHandleTable = IOHandleTable{}
|
|
|
|
|
2023-11-05 13:31:33 +00:00
|
|
|
//export hcl_go_cci_handler
|
|
|
|
func hcl_go_cci_handler(c *C.hcl_t, cmd C.hcl_io_cmd_t, arg unsafe.Pointer) C.int {
|
2023-10-27 09:20:02 +00:00
|
|
|
var (
|
|
|
|
g *HCL
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
g = c_to_go(c)
|
|
|
|
|
|
|
|
switch cmd {
|
|
|
|
case C.HCL_IO_OPEN:
|
|
|
|
var (
|
2023-11-05 13:31:33 +00:00
|
|
|
ioarg *C.hcl_io_cciarg_t
|
2023-10-27 09:20:02 +00:00
|
|
|
name string
|
|
|
|
includer_name string
|
|
|
|
fd int
|
|
|
|
)
|
|
|
|
|
2023-11-05 13:31:33 +00:00
|
|
|
ioarg = (*C.hcl_io_cciarg_t)(arg)
|
2023-10-27 09:20:02 +00:00
|
|
|
if ioarg.name == nil { // main stream when it's not feed based.
|
|
|
|
name = ""
|
|
|
|
} else {
|
|
|
|
var k []rune = ucstr_to_rune_slice(ioarg.name)
|
|
|
|
name = string(k)
|
|
|
|
}
|
|
|
|
|
|
|
|
if ioarg.includer == nil || ioarg.includer.name == nil {
|
2023-11-05 14:33:22 +00:00
|
|
|
includer_name = g.io.cci_main
|
2023-10-27 09:20:02 +00:00
|
|
|
} else {
|
|
|
|
var k []rune = ucstr_to_rune_slice(ioarg.includer.name)
|
|
|
|
includer_name = string(k)
|
|
|
|
}
|
|
|
|
|
2023-11-05 14:33:22 +00:00
|
|
|
fd, err = g.io.cci.Open(g, name, includer_name)
|
2023-10-27 09:20:02 +00:00
|
|
|
if err != nil {
|
2023-11-05 14:33:22 +00:00
|
|
|
g.set_errmsg(C.HCL_EIOERR, err.Error())
|
2023-10-27 09:20:02 +00:00
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
ioarg.handle = unsafe.Pointer(uintptr(fd))
|
|
|
|
return 0
|
|
|
|
|
|
|
|
case C.HCL_IO_CLOSE:
|
2023-11-05 13:31:33 +00:00
|
|
|
var ioarg *C.hcl_io_cciarg_t = (*C.hcl_io_cciarg_t)(arg)
|
2023-11-05 14:33:22 +00:00
|
|
|
g.io.cci.Close(int(uintptr(ioarg.handle)))
|
2023-10-27 09:20:02 +00:00
|
|
|
return 0
|
|
|
|
|
|
|
|
case C.HCL_IO_READ:
|
|
|
|
var (
|
2023-11-05 13:31:33 +00:00
|
|
|
ioarg *C.hcl_io_cciarg_t
|
2023-10-27 09:20:02 +00:00
|
|
|
n int
|
|
|
|
i int
|
|
|
|
buf []rune
|
|
|
|
)
|
2023-11-05 13:31:33 +00:00
|
|
|
ioarg = (*C.hcl_io_cciarg_t)(arg)
|
2023-10-27 09:20:02 +00:00
|
|
|
|
|
|
|
buf = make([]rune, 1024) // TODO: different size...
|
2023-11-05 14:33:22 +00:00
|
|
|
n, err = g.io.cci.Read(int(uintptr(ioarg.handle)), buf)
|
2023-10-27 09:20:02 +00:00
|
|
|
if err != nil {
|
2023-11-05 14:33:22 +00:00
|
|
|
g.set_errmsg(C.HCL_EIOERR, err.Error())
|
2023-10-27 09:20:02 +00:00
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
for i = 0; i < n; i++ { // TODO: use a proper conversion when the rune size is different from hio_uch_t
|
|
|
|
ioarg.buf[i] = C.hcl_uch_t(buf[i])
|
|
|
|
}
|
|
|
|
ioarg.xlen = C.hcl_oow_t(n)
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2023-11-01 07:06:28 +00:00
|
|
|
C.hcl_seterrnum(c, C.HCL_EIOERR)
|
2023-10-27 09:20:02 +00:00
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
2023-11-05 13:31:33 +00:00
|
|
|
//export hcl_go_udi_handler
|
|
|
|
func hcl_go_udi_handler(c *C.hcl_t, cmd C.hcl_io_cmd_t, arg unsafe.Pointer) C.int {
|
2023-10-27 09:20:02 +00:00
|
|
|
var (
|
|
|
|
g *HCL
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
g = c_to_go(c)
|
|
|
|
|
|
|
|
switch cmd {
|
|
|
|
case C.HCL_IO_OPEN:
|
2023-11-05 14:33:22 +00:00
|
|
|
err = g.io.udi.Open(g)
|
2023-10-27 09:20:02 +00:00
|
|
|
if err != nil {
|
2023-11-05 14:33:22 +00:00
|
|
|
g.set_errmsg(C.HCL_EIOERR, err.Error())
|
2023-10-27 09:20:02 +00:00
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
// we don't need to set ioarg.handle because the c object to go object
|
|
|
|
// mapping has been established and it doesn't handle multiple streams
|
|
|
|
return 0
|
|
|
|
|
|
|
|
case C.HCL_IO_CLOSE:
|
2023-11-05 14:33:22 +00:00
|
|
|
g.io.udi.Close()
|
2023-10-27 09:20:02 +00:00
|
|
|
return 0
|
|
|
|
|
|
|
|
case C.HCL_IO_READ:
|
|
|
|
var (
|
2023-11-05 07:58:45 +00:00
|
|
|
ioarg *C.hcl_io_udiarg_t
|
2023-10-27 09:20:02 +00:00
|
|
|
n int
|
|
|
|
err error
|
|
|
|
buf []rune
|
|
|
|
)
|
2023-11-05 07:58:45 +00:00
|
|
|
ioarg = (*C.hcl_io_udiarg_t)(arg)
|
2023-10-27 09:20:02 +00:00
|
|
|
|
|
|
|
buf = make([]rune, 1024) // TODO: different size...
|
2023-11-05 14:33:22 +00:00
|
|
|
n, err = g.io.udi.Read(buf)
|
2023-10-27 09:20:02 +00:00
|
|
|
if err != nil {
|
2023-11-05 14:33:22 +00:00
|
|
|
g.set_errmsg(C.HCL_EIOERR, err.Error())
|
2023-10-27 09:20:02 +00:00
|
|
|
return -1
|
|
|
|
}
|
|
|
|
ioarg.xlen = C.ulong(n)
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2023-11-01 07:06:28 +00:00
|
|
|
C.hcl_seterrnum(c, C.HCL_EIOERR)
|
2023-10-27 09:20:02 +00:00
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
2023-11-05 13:31:33 +00:00
|
|
|
//export hcl_go_udo_handler
|
|
|
|
func hcl_go_udo_handler(c *C.hcl_t, cmd C.hcl_io_cmd_t, arg unsafe.Pointer) C.int {
|
2023-10-27 09:20:02 +00:00
|
|
|
var (
|
|
|
|
g *HCL
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
g = c_to_go(c)
|
|
|
|
|
|
|
|
switch cmd {
|
|
|
|
case C.HCL_IO_OPEN:
|
2023-11-05 14:33:22 +00:00
|
|
|
err = g.io.udo.Open(g)
|
2023-10-27 09:20:02 +00:00
|
|
|
if err != nil {
|
2023-11-05 14:33:22 +00:00
|
|
|
g.set_errmsg(C.HCL_EIOERR, err.Error())
|
2023-10-27 09:20:02 +00:00
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
// we don't need to set ioarg.handle because the c object to go object
|
|
|
|
// mapping has been established and it doesn't handle multiple streams
|
|
|
|
return 0
|
|
|
|
|
|
|
|
case C.HCL_IO_CLOSE:
|
2023-11-05 14:33:22 +00:00
|
|
|
g.io.udo.Close()
|
2023-10-27 09:20:02 +00:00
|
|
|
return 0
|
|
|
|
|
|
|
|
case C.HCL_IO_WRITE:
|
|
|
|
var (
|
2023-11-05 07:58:45 +00:00
|
|
|
ioarg *C.hcl_io_udoarg_t
|
2023-10-27 09:20:02 +00:00
|
|
|
data []rune
|
|
|
|
err error
|
|
|
|
)
|
2023-11-05 07:58:45 +00:00
|
|
|
ioarg = (*C.hcl_io_udoarg_t)(arg)
|
2023-10-27 09:20:02 +00:00
|
|
|
data = uchars_to_rune_slice((*C.hcl_uch_t)(ioarg.ptr), uintptr(ioarg.len))
|
2023-11-05 14:33:22 +00:00
|
|
|
err = g.io.udo.Write(data)
|
2023-10-27 09:20:02 +00:00
|
|
|
if err != nil {
|
2023-11-05 14:33:22 +00:00
|
|
|
g.set_errmsg(C.HCL_EIOERR, err.Error())
|
2023-10-27 09:20:02 +00:00
|
|
|
return -1
|
|
|
|
}
|
|
|
|
ioarg.xlen = C.hcl_oow_t(len(data))
|
|
|
|
return 0
|
|
|
|
|
|
|
|
case C.HCL_IO_WRITE_BYTES:
|
|
|
|
var (
|
2023-11-05 07:58:45 +00:00
|
|
|
ioarg *C.hcl_io_udoarg_t
|
2023-10-27 09:20:02 +00:00
|
|
|
data []byte
|
|
|
|
err error
|
|
|
|
)
|
2023-11-05 07:58:45 +00:00
|
|
|
ioarg = (*C.hcl_io_udoarg_t)(arg)
|
2023-10-27 09:20:02 +00:00
|
|
|
data = unsafe.Slice((*byte)(ioarg.ptr), ioarg.len)
|
2023-11-05 14:33:22 +00:00
|
|
|
err = g.io.udo.WriteBytes(data)
|
2023-10-27 09:20:02 +00:00
|
|
|
if err != nil {
|
2023-11-05 14:33:22 +00:00
|
|
|
g.set_errmsg(C.HCL_EIOERR, err.Error())
|
2023-10-27 09:20:02 +00:00
|
|
|
return -1
|
|
|
|
}
|
|
|
|
ioarg.xlen = C.hcl_oow_t(len(data))
|
|
|
|
return 0
|
|
|
|
|
|
|
|
case C.HCL_IO_FLUSH:
|
2023-11-05 14:33:22 +00:00
|
|
|
var err error = g.io.udo.Flush()
|
2023-10-27 09:20:02 +00:00
|
|
|
if err != nil {
|
2023-11-05 14:33:22 +00:00
|
|
|
g.set_errmsg(C.HCL_EIOERR, err.Error())
|
2023-10-27 09:20:02 +00:00
|
|
|
return -1
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2023-11-01 07:06:28 +00:00
|
|
|
C.hcl_seterrnum(c, C.HCL_EIOERR)
|
2023-10-27 09:20:02 +00:00
|
|
|
return -1
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------
|
2023-11-05 13:31:33 +00:00
|
|
|
type CciFileHandler struct {
|
2023-10-27 09:20:02 +00:00
|
|
|
g *HCL
|
|
|
|
}
|
|
|
|
|
2023-11-05 13:31:33 +00:00
|
|
|
func (p *CciFileHandler) Open(g *HCL, name string, includer_name string) (int, error) {
|
2023-10-27 09:20:02 +00:00
|
|
|
var (
|
|
|
|
f *os.File
|
|
|
|
r *bufio.Reader
|
|
|
|
fd int
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
if name == "" {
|
|
|
|
f = os.Stdin
|
|
|
|
} else {
|
2023-11-05 14:33:22 +00:00
|
|
|
var dir string
|
|
|
|
|
|
|
|
dir = path.Dir(includer_name)
|
|
|
|
if dir != "/" && dir != "" {
|
|
|
|
dir = dir + "/"
|
|
|
|
}
|
|
|
|
|
|
|
|
f, err = os.Open(dir + name)
|
2023-10-27 09:20:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return -1, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r = bufio.NewReader(f)
|
|
|
|
fd = io_tab.add_io_handle(f, r)
|
|
|
|
|
|
|
|
p.g = g
|
|
|
|
return fd, nil
|
|
|
|
}
|
|
|
|
|
2023-11-05 13:31:33 +00:00
|
|
|
func (p *CciFileHandler) Close(fd int) {
|
2023-10-27 09:20:02 +00:00
|
|
|
var hnd IOHandle = io_tab.slot_to_io_handle(fd)
|
|
|
|
if hnd.file != nil {
|
|
|
|
if hnd.file != os.Stdout && hnd.file != os.Stderr {
|
|
|
|
hnd.file.Close()
|
|
|
|
}
|
|
|
|
hnd.file = nil
|
|
|
|
hnd.ioif = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-05 13:31:33 +00:00
|
|
|
func (p *CciFileHandler) Read(fd int, buf []rune) (int, error) {
|
2023-10-27 09:20:02 +00:00
|
|
|
var (
|
|
|
|
hnd IOHandle
|
|
|
|
i int
|
|
|
|
c rune
|
|
|
|
r *bufio.Reader
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
hnd = io_tab.slot_to_io_handle(fd)
|
|
|
|
r, _ = hnd.ioif.(*bufio.Reader)
|
|
|
|
for i = 0; i < len(buf); i++ {
|
|
|
|
c, _, err = r.ReadRune()
|
|
|
|
if err == io.EOF {
|
|
|
|
break
|
|
|
|
} else if err != nil {
|
|
|
|
return -1, err
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[i] = c
|
|
|
|
}
|
|
|
|
|
|
|
|
return i, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------
|
2023-11-05 13:31:33 +00:00
|
|
|
type UdiFileHandler struct {
|
2023-10-27 09:20:02 +00:00
|
|
|
g *HCL
|
|
|
|
f *os.File
|
|
|
|
r *bufio.Reader
|
|
|
|
}
|
|
|
|
|
2023-11-05 13:31:33 +00:00
|
|
|
func (p *UdiFileHandler) Open(g *HCL) error {
|
2023-10-27 09:20:02 +00:00
|
|
|
var (
|
|
|
|
f *os.File
|
|
|
|
// err error
|
|
|
|
)
|
|
|
|
|
|
|
|
f = os.Stdin
|
2023-10-31 12:17:08 +00:00
|
|
|
//f, err = os.Open("/dev/stdin")
|
|
|
|
//if err != nil {
|
|
|
|
// return err
|
|
|
|
//}
|
2023-10-27 09:20:02 +00:00
|
|
|
|
|
|
|
p.r = bufio.NewReader(f)
|
|
|
|
p.f = f
|
|
|
|
p.g = g
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-11-05 13:31:33 +00:00
|
|
|
func (p *UdiFileHandler) Close() {
|
2023-10-27 09:20:02 +00:00
|
|
|
if p.f != nil {
|
|
|
|
if p.f != os.Stdout && p.f != os.Stderr {
|
|
|
|
p.f.Close()
|
|
|
|
}
|
|
|
|
p.f = nil
|
|
|
|
p.r = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-05 13:31:33 +00:00
|
|
|
func (p *UdiFileHandler) Read(buf []rune) (int, error) {
|
2023-10-27 09:20:02 +00:00
|
|
|
var (
|
|
|
|
i int
|
|
|
|
c rune
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
// flush all pending print out before reading
|
2023-11-05 14:33:22 +00:00
|
|
|
p.g.io.udo.Flush()
|
2023-10-27 09:20:02 +00:00
|
|
|
|
|
|
|
for i = 0; i < len(buf); i++ {
|
|
|
|
c, _, err = p.r.ReadRune()
|
|
|
|
if err == io.EOF {
|
|
|
|
break
|
|
|
|
} else if err != nil {
|
|
|
|
return -1, err
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[i] = c
|
|
|
|
}
|
|
|
|
|
|
|
|
return i, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------
|
|
|
|
|
2023-11-05 13:31:33 +00:00
|
|
|
type UdoFileHandler struct {
|
2023-10-27 09:20:02 +00:00
|
|
|
f *os.File
|
|
|
|
w *bufio.Writer
|
|
|
|
}
|
|
|
|
|
2023-11-05 13:31:33 +00:00
|
|
|
func (p *UdoFileHandler) Open(g *HCL) error {
|
2023-10-27 09:20:02 +00:00
|
|
|
var (
|
|
|
|
f *os.File
|
|
|
|
// err error
|
|
|
|
)
|
2023-10-29 17:30:19 +00:00
|
|
|
|
2023-10-31 12:17:08 +00:00
|
|
|
// f, err = os.OpenFile("/dev/stdout", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
|
|
|
// if err != nil {
|
|
|
|
// return err
|
|
|
|
// }
|
2023-10-27 09:20:02 +00:00
|
|
|
|
|
|
|
f = os.Stdout
|
|
|
|
|
|
|
|
p.w = bufio.NewWriter(f)
|
|
|
|
p.f = f
|
|
|
|
|
|
|
|
//fmt.Fprintf(os.Stderr, "XXXXXXXXXX open porint\n")
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-11-05 13:31:33 +00:00
|
|
|
func (p *UdoFileHandler) Close() {
|
2023-10-27 09:20:02 +00:00
|
|
|
|
|
|
|
//fmt.Fprintf(os.Stderr, "XXXXXXXXXX close porint\n")
|
|
|
|
if p.f != nil {
|
|
|
|
if p.f != os.Stdout && p.f != os.Stderr {
|
|
|
|
p.f.Close()
|
|
|
|
}
|
|
|
|
p.f = nil
|
|
|
|
p.w = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-05 13:31:33 +00:00
|
|
|
func (p *UdoFileHandler) Write(data []rune) error {
|
2023-10-27 09:20:02 +00:00
|
|
|
var err error
|
|
|
|
|
|
|
|
//fmt.Fprintf(os.Stderr, "XXXXXXXXXX write porint\n")
|
|
|
|
_, err = p.w.WriteString(string(data))
|
|
|
|
p.w.Flush() // TODO: is this needed?
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-11-05 13:31:33 +00:00
|
|
|
func (p *UdoFileHandler) WriteBytes(data []byte) error {
|
2023-10-27 09:20:02 +00:00
|
|
|
var err error
|
|
|
|
|
|
|
|
//fmt.Fprintf(os.Stderr, "XXXXXXXXXX write porint\n")
|
|
|
|
_, err = p.w.Write(data)
|
|
|
|
p.w.Flush() // TODO: is this needed?
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-11-05 13:31:33 +00:00
|
|
|
func (p *UdoFileHandler) Flush() error {
|
2023-10-27 09:20:02 +00:00
|
|
|
//fmt.Fprintf(os.Stderr, "XXXXXXXXXX flush porint\n")
|
|
|
|
return p.w.Flush()
|
|
|
|
}
|