1675 lines
40 KiB
Go
1675 lines
40 KiB
Go
// Copyright 2020 The Libc Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package libc // import "modernc.org/libc"
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
mbits "math/bits"
|
|
"os"
|
|
"reflect"
|
|
"runtime"
|
|
"runtime/debug"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"sync/atomic"
|
|
"syscall"
|
|
//UCRT "unicode"
|
|
"unicode/utf16"
|
|
"unsafe"
|
|
|
|
"modernc.org/mathutil"
|
|
"modernc.org/memory"
|
|
)
|
|
|
|
const iobEntries = 20
|
|
|
|
var (
|
|
allocator memory.Allocator
|
|
allocatorMu sync.Mutex
|
|
cR = [...]byte{'r', 0}
|
|
cW = [...]byte{'w', 0}
|
|
dll = syscall.NewLazyDLL("ucrtbase.dll")
|
|
iob [iobEntries]uintptr
|
|
isWindows = true
|
|
kdll = syscall.NewLazyDLL("kernel32.dll")
|
|
objects = map[uintptr]any{}
|
|
objectsMu sync.Mutex
|
|
threadCallback uintptr
|
|
token atomic.Uintptr
|
|
uintptrSize = unsafe.Sizeof(uintptr(0))
|
|
|
|
wenvValid atomic.Bool
|
|
wenviron uintptr
|
|
winEnviron = []uintptr{0}
|
|
)
|
|
|
|
var X__imp__wenviron = uintptr(unsafe.Pointer(&wenviron))
|
|
var X_imp___wenviron = uintptr(unsafe.Pointer(&wenviron))
|
|
var Xin6addr_any [16]byte
|
|
var Xstderr uintptr
|
|
var Xstdin uintptr
|
|
var Xstdout uintptr
|
|
var Xtimezone long // extern long timezone;
|
|
|
|
func init() {
|
|
threadCallback = syscall.NewCallback(threadProc)
|
|
iob[0] = X_fdopen(nil, 0, uintptr(unsafe.Pointer(&cR[0])))
|
|
iob[1] = X_fdopen(nil, 1, uintptr(unsafe.Pointer(&cW[0])))
|
|
iob[2] = X_fdopen(nil, 2, uintptr(unsafe.Pointer(&cW[0])))
|
|
Xstdin = iob[0]
|
|
Xstdout = iob[1]
|
|
Xstderr = iob[2]
|
|
}
|
|
|
|
func addObject(o any) uintptr {
|
|
t := token.Add(1)
|
|
objectsMu.Lock()
|
|
objects[t] = o
|
|
objectsMu.Unlock()
|
|
return t
|
|
}
|
|
|
|
func getObject(t uintptr) (r any) {
|
|
objectsMu.Lock()
|
|
r = objects[t]
|
|
objectsMu.Unlock()
|
|
return r
|
|
}
|
|
|
|
func removeObject(t uintptr) {
|
|
objectsMu.Lock()
|
|
delete(objects, t)
|
|
objectsMu.Unlock()
|
|
}
|
|
|
|
//TODO- type MemAuditError struct {
|
|
//TODO- Caller string
|
|
//TODO- Message string
|
|
//TODO- }
|
|
|
|
type long = int32
|
|
type ulong = uint32
|
|
|
|
type threadAdapter struct {
|
|
token uintptr
|
|
tls *TLS
|
|
param uintptr
|
|
threadFunc func(*TLS, uintptr) uint32
|
|
}
|
|
|
|
func (t *threadAdapter) run() uintptr {
|
|
runtime.LockOSThread()
|
|
|
|
t.tls.token = t.token
|
|
r := (t.threadFunc(t.tls, t.param))
|
|
t.tls.endthread(r)
|
|
return uintptr(r)
|
|
}
|
|
|
|
func threadProc(p uintptr) uintptr {
|
|
adp, ok := getObject(p).(*threadAdapter)
|
|
if !ok {
|
|
panic("invalid thread")
|
|
}
|
|
|
|
return adp.run()
|
|
}
|
|
|
|
var procCreateThread = kdll.NewProc("CreateThread")
|
|
var _ = procCreateThread.Addr()
|
|
|
|
// libkernel32: __attribute__((dllimport)) HANDLE CreateThread (LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);
|
|
func CreateThread(tls *TLS, attr uintptr, stackSize Tsize_t, fn uintptr, param uintptr, flags uint32, threadID uintptr) (r uintptr) {
|
|
f := (*struct {
|
|
f func(*TLS, uintptr) uint32
|
|
})(unsafe.Pointer(&struct{ uintptr }{fn})).f
|
|
var adapter = threadAdapter{threadFunc: f, tls: NewTLS(), param: param}
|
|
adapter.token = addObject(&adapter)
|
|
r0, _, _ := syscall.SyscallN(procCreateThread.Addr(), attr, uintptr(stackSize), threadCallback, adapter.token, uintptr(flags), threadID)
|
|
return r0
|
|
}
|
|
|
|
// __attribute__ ((__dllimport__)) uintptr_t __attribute__((__cdecl__)) _beginthread(_beginthread_proc_type _StartAddress,unsigned _StackSize,void *_ArgList);
|
|
func X_beginthread(tls *TLS, __StartAddress T_beginthread_proc_type, __StackSize uint32, __ArgList uintptr) (r Tuintptr_t) {
|
|
f := (*struct {
|
|
f func(*TLS, uintptr) uint32
|
|
})(unsafe.Pointer(&struct{ uintptr }{__StartAddress})).f
|
|
var adapter = threadAdapter{threadFunc: f, tls: NewTLS(), param: __ArgList}
|
|
adapter.token = addObject(&adapter)
|
|
r0, _, _ := syscall.SyscallN(procCreateThread.Addr(), 0, uintptr(__StackSize), threadCallback, adapter.token, 0, 0)
|
|
return Tuintptr_t(r0)
|
|
}
|
|
|
|
// __attribute__ ((__dllimport__)) uintptr_t __attribute__((__cdecl__)) _beginthreadex(void *_Security,unsigned _StackSize,_beginthreadex_proc_type _StartAddress,void *_ArgList,unsigned _InitFlag,unsigned *_ThrdAddr);
|
|
func X_beginthreadex(tls *TLS, __Security uintptr, __StackSize uint32, __StartAddress T_beginthreadex_proc_type, __ArgList uintptr, __InitFlag uint32, __ThrdAddr uintptr) (r Tuintptr_t) {
|
|
f := (*struct {
|
|
f func(*TLS, uintptr) uint32
|
|
})(unsafe.Pointer(&struct{ uintptr }{__StartAddress})).f
|
|
var adapter = threadAdapter{threadFunc: f, tls: NewTLS(), param: __ArgList}
|
|
adapter.token = addObject(&adapter)
|
|
r0, _, _ := syscall.SyscallN(procCreateThread.Addr(), 0, uintptr(__StackSize), threadCallback, adapter.token, 0, 0)
|
|
return Tuintptr_t(r0)
|
|
}
|
|
|
|
// __attribute__ ((__dllimport__)) void __attribute__((__cdecl__)) _endthreadex(unsigned _Retval) __attribute__ ((__noreturn__));
|
|
func X_endthreadex(tls *TLS, __Retval uint32) {
|
|
tls.endthread(__Retval)
|
|
}
|
|
|
|
func Start(main func(*TLS, int32, uintptr) int32) {
|
|
runtime.LockOSThread()
|
|
argv := Xcalloc(nil, 1, Tsize_t((len(os.Args)+1)*int(uintptrSize)))
|
|
if argv == 0 {
|
|
panic("OOM")
|
|
}
|
|
|
|
p := argv
|
|
for _, v := range os.Args {
|
|
s := Xcalloc(nil, 1, Tsize_t(len(v)+1))
|
|
if s == 0 {
|
|
panic("OOM")
|
|
}
|
|
|
|
copy(unsafe.Slice((*byte)(unsafe.Pointer(s)), len(v)), v)
|
|
*(*uintptr)(unsafe.Pointer(p)) = s
|
|
p += uintptrSize
|
|
}
|
|
t := NewTLS()
|
|
rc := main(t, int32(len(os.Args)), argv)
|
|
Xexit(t, rc)
|
|
}
|
|
|
|
type tlsStackSlot struct {
|
|
p uintptr
|
|
sz Tsize_t
|
|
}
|
|
|
|
// TLS emulates thread local storage. TLS is not safe for concurrent use by
|
|
// multiple goroutines.
|
|
type TLS struct {
|
|
errnop uintptr
|
|
lastError uint32 // libkernel32.{SetLastError,GetLastError}
|
|
stack []tlsStackSlot
|
|
token uintptr
|
|
|
|
retval uint32
|
|
sp int
|
|
|
|
exited bool
|
|
}
|
|
|
|
// NewTLS returns a newly created TLS that must be eventually closed to prevent
|
|
// resource leaks.
|
|
func NewTLS() (r *TLS) {
|
|
p := mustMalloc(Tsize_t(unsafe.Sizeof(int32(0))))
|
|
*(*int32)(unsafe.Pointer(p)) = 0
|
|
return &TLS{
|
|
errnop: p,
|
|
}
|
|
}
|
|
|
|
var procexit = dll.NewProc("exit")
|
|
var _ = procexit.Addr()
|
|
|
|
// void __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) exit(int _Code) __attribute__ ((__noreturn__));
|
|
func Xexit(tls *TLS, __Code int32) {
|
|
Xfflush(tls, Xstdout)
|
|
Xfflush(tls, Xstderr)
|
|
syscall.SyscallN(procexit.Addr(), uintptr(__Code))
|
|
}
|
|
|
|
func (tls *TLS) endthread(retval uint32) {
|
|
if tls == nil || tls.exited {
|
|
return
|
|
}
|
|
|
|
tls.exited = true
|
|
tls.retval = retval
|
|
tls.Close()
|
|
removeObject(tls.token)
|
|
runtime.UnlockOSThread()
|
|
}
|
|
|
|
func (tls *TLS) SetLastError(_dwErrCode uint32) {
|
|
if tls != nil {
|
|
tls.lastError = _dwErrCode
|
|
}
|
|
}
|
|
|
|
// https://github.com/golang/go/issues/41220
|
|
|
|
func (tls *TLS) GetLastError() (r uint32) {
|
|
if tls == nil {
|
|
return 0
|
|
}
|
|
|
|
return tls.lastError
|
|
}
|
|
|
|
func (tls *TLS) setErrno(n int32) {
|
|
if __ccgo_strace {
|
|
trc("errno<-%v", n)
|
|
}
|
|
if tls == nil {
|
|
return
|
|
}
|
|
|
|
*(*int32)(unsafe.Pointer(tls.errnop)) = n
|
|
}
|
|
|
|
func X___errno_location(t *TLS) uintptr {
|
|
return t.errnop
|
|
}
|
|
|
|
// int * __errno_location(void);
|
|
func X__errno_location(t *TLS) uintptr {
|
|
return t.errnop
|
|
}
|
|
|
|
// __attribute__ ((__dllimport__)) extern int * __attribute__((__cdecl__)) _errno(void);
|
|
func X_errno(tls *TLS) (r uintptr) {
|
|
return tls.errnop
|
|
}
|
|
|
|
func malloc(n Tsize_t) (r uintptr) {
|
|
allocatorMu.Lock()
|
|
|
|
defer allocatorMu.Unlock()
|
|
|
|
if r, _ = allocator.UintptrMalloc(int(n)); r == 0 {
|
|
panic("OOM")
|
|
}
|
|
|
|
return r
|
|
}
|
|
|
|
func free(p uintptr) {
|
|
allocatorMu.Lock()
|
|
|
|
defer allocatorMu.Unlock()
|
|
|
|
allocator.UintptrFree(p)
|
|
}
|
|
|
|
func malloc_usable_size(p uintptr) (r Tsize_t) {
|
|
if p == 0 {
|
|
return 0
|
|
}
|
|
|
|
allocatorMu.Lock()
|
|
|
|
defer allocatorMu.Unlock()
|
|
|
|
return Tsize_t(memory.UintptrUsableSize(p))
|
|
}
|
|
|
|
func (tls *TLS) Close() {
|
|
if tls == nil {
|
|
return
|
|
}
|
|
|
|
// for _, v := range tls.allocas {
|
|
// free(tls, v)
|
|
// }
|
|
for _, v := range tls.stack /* shrink diabled[:tls.sp] */ {
|
|
free(v.p)
|
|
}
|
|
}
|
|
|
|
func (tls *TLS) Alloc(n0 int) (r uintptr) {
|
|
const shrinkSegment = 32
|
|
n := Tsize_t(n0)
|
|
if tls.sp < len(tls.stack) {
|
|
p := tls.stack[tls.sp].p
|
|
sz := tls.stack[tls.sp].sz
|
|
if sz >= n /* && sz <= shrinkSegment*n */ {
|
|
// Segment shrinking is nice to have but Tcl does some dirty hacks in coroutine
|
|
// handling that require stability of stack addresses, out of the C execution
|
|
// model. Disabled.
|
|
tls.sp++
|
|
return p
|
|
}
|
|
|
|
free(p)
|
|
r = malloc(n)
|
|
tls.stack[tls.sp] = tlsStackSlot{p: r, sz: malloc_usable_size(r)}
|
|
tls.sp++
|
|
return r
|
|
|
|
}
|
|
|
|
r = malloc(n)
|
|
tls.stack = append(tls.stack, tlsStackSlot{p: r, sz: malloc_usable_size(r)})
|
|
tls.sp++
|
|
return r
|
|
}
|
|
|
|
// Free manages memory of the preceding TLS.Alloc()
|
|
func (tls *TLS) Free(n int) {
|
|
tls.sp--
|
|
}
|
|
|
|
// VaList fills a varargs list at p with args and returns p. The list must
|
|
// have been allocated by the caller and it must not be in Go managed memory,
|
|
// ie. it must be pinned. The caller is responsible for freeing the list.
|
|
//
|
|
// This function supports code generated by ccgo/v4.
|
|
//
|
|
// Note: The C translated to Go varargs ABI alignment for all types is 8 on all
|
|
// architectures.
|
|
func VaList(p uintptr, args ...interface{}) (r uintptr) {
|
|
if p&7 != 0 {
|
|
panic("internal error")
|
|
}
|
|
|
|
r = p
|
|
for _, v := range args {
|
|
switch x := v.(type) {
|
|
case int:
|
|
*(*int64)(unsafe.Pointer(p)) = int64(x)
|
|
case int32:
|
|
*(*int64)(unsafe.Pointer(p)) = int64(x)
|
|
case int64:
|
|
*(*int64)(unsafe.Pointer(p)) = x
|
|
case uint:
|
|
*(*uint64)(unsafe.Pointer(p)) = uint64(x)
|
|
case uint16:
|
|
*(*uint64)(unsafe.Pointer(p)) = uint64(x)
|
|
case uint32:
|
|
*(*uint64)(unsafe.Pointer(p)) = uint64(x)
|
|
case uint64:
|
|
*(*uint64)(unsafe.Pointer(p)) = x
|
|
case float64:
|
|
*(*float64)(unsafe.Pointer(p)) = x
|
|
case uintptr:
|
|
*(*uintptr)(unsafe.Pointer(p)) = x
|
|
default:
|
|
sz := reflect.TypeOf(v).Size()
|
|
copy(unsafe.Slice((*byte)(unsafe.Pointer(p)), sz), unsafe.Slice((*byte)(unsafe.Pointer((*[2]uintptr)(unsafe.Pointer(&v))[1])), sz))
|
|
p += roundup(sz, 8)
|
|
continue
|
|
}
|
|
p += 8
|
|
}
|
|
return r
|
|
}
|
|
|
|
func roundup(n, to uintptr) uintptr {
|
|
if r := n % to; r != 0 {
|
|
return n + to - r
|
|
}
|
|
|
|
return n
|
|
}
|
|
|
|
func mustMalloc(sz Tsize_t) (r uintptr) {
|
|
if r = Xmalloc(nil, sz); r != 0 || sz == 0 {
|
|
return r
|
|
}
|
|
|
|
panic("OOM")
|
|
}
|
|
|
|
// CString returns a pointer to a zero-terminated version of s. The caller is
|
|
// responsible for freeing the allocated memory using Xfree.
|
|
func CString(s string) (uintptr, error) {
|
|
n := len(s)
|
|
p := Xmalloc(nil, Tsize_t(n)+1)
|
|
if p == 0 {
|
|
return 0, fmt.Errorf("CString: cannot allocate %d bytes", n+1)
|
|
}
|
|
|
|
copy(unsafe.Slice((*byte)(unsafe.Pointer(p)), n), s)
|
|
*(*byte)(unsafe.Pointer(p + uintptr(n))) = 0
|
|
return p, nil
|
|
}
|
|
|
|
// GoBytes returns a byte slice from a C char* having length len bytes.
|
|
func GoBytes(s uintptr, len int) []byte {
|
|
return unsafe.Slice((*byte)(unsafe.Pointer(s)), len)
|
|
}
|
|
|
|
// GoString returns the value of a C string at s.
|
|
func GoString(s uintptr) string {
|
|
if s == 0 {
|
|
return ""
|
|
}
|
|
|
|
var buf []byte
|
|
for {
|
|
b := *(*byte)(unsafe.Pointer(s))
|
|
if b == 0 {
|
|
return string(buf)
|
|
}
|
|
|
|
buf = append(buf, b)
|
|
s++
|
|
}
|
|
}
|
|
|
|
func X__ccgo_SyscallFP() {
|
|
s := fmt.Sprintf("%s\nTODO syscall: function pointer", debug.Stack())
|
|
panic(s)
|
|
}
|
|
|
|
func Bool(v bool) bool { return v }
|
|
|
|
func Bool32(b bool) int32 {
|
|
if b {
|
|
return 1
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func fwrite(tls *TLS, f uintptr, b []byte) (int, error) {
|
|
if len(b) == 0 {
|
|
return 0, nil
|
|
}
|
|
|
|
n := Xfwrite(tls, uintptr(unsafe.Pointer(&b[0])), 1, Tsize_t(len(b)), f)
|
|
if int(n) != len(b) {
|
|
return int(n), fmt.Errorf("short write")
|
|
}
|
|
|
|
return len(b), nil
|
|
}
|
|
|
|
// int fprintf(FILE *stream, const char *format, ...);
|
|
func Xfprintf(tls *TLS, stream, format, args uintptr) int32 {
|
|
n, _ := fwrite(tls, stream, printf(format, args))
|
|
return int32(n)
|
|
}
|
|
|
|
func X__acrt_iob_func(tls *TLS, _index uint32) (r uintptr) {
|
|
return iob[_index]
|
|
}
|
|
|
|
// extern __attribute__((__format__ (gnu_printf, 2, 0))) __attribute__ ((__nonnull__ (2))) int __attribute__((__cdecl__)) __mingw_vfprintf (FILE * __restrict__ , const char * __restrict__ , va_list) __attribute__ ((__nothrow__));
|
|
func X__mingw_vfprintf(tls *TLS, _0 uintptr, _1 uintptr, _2 Tva_list) (r int32) {
|
|
return Xvfprintf(tls, _0, _1, _2)
|
|
}
|
|
|
|
func X__mingw_vsprintf(tls *TLS, _0 uintptr, _1 uintptr, _2 Tva_list) (r int32) {
|
|
return Xvsprintf(tls, _0, _1, _2)
|
|
}
|
|
|
|
func X__builtin_inff(tls *TLS) float32 {
|
|
return float32(math.Inf(1))
|
|
}
|
|
|
|
func X__builtin_nanf(tls *TLS, s uintptr) float32 {
|
|
return float32(math.NaN())
|
|
}
|
|
|
|
func X__builtin_printf(tls *TLS, fmt uintptr, va uintptr) (r int32) {
|
|
return Xprintf(tls, fmt, va)
|
|
}
|
|
|
|
func X__builtin_round(tls *TLS, x float64) (r float64) {
|
|
return Xround(tls, x)
|
|
}
|
|
|
|
func X__builtin_roundf(tls *TLS, x float32) (r float32) {
|
|
return Xroundf(tls, x)
|
|
}
|
|
|
|
func X__builtin_expect(t *TLS, exp, c long) long {
|
|
return exp
|
|
}
|
|
|
|
func X__builtin_abort(t *TLS) {
|
|
Xabort(t)
|
|
}
|
|
|
|
func X__builtin_abs(t *TLS, j int32) int32 {
|
|
return Xabs(t, j)
|
|
}
|
|
|
|
func X__builtin_ctz(t *TLS, n uint32) int32 {
|
|
return int32(mbits.TrailingZeros32(n))
|
|
}
|
|
|
|
func X__builtin_clz(t *TLS, n uint32) int32 {
|
|
return int32(mbits.LeadingZeros32(n))
|
|
}
|
|
|
|
func X__builtin_clzl(t *TLS, n ulong) int32 {
|
|
return int32(mbits.LeadingZeros32(n))
|
|
}
|
|
|
|
func X__builtin_clzll(t *TLS, n uint64) int32 {
|
|
return int32(mbits.LeadingZeros64(n))
|
|
}
|
|
|
|
func X__builtin_constant_p_impl() { panic("internal error: should never be called") }
|
|
|
|
func X__builtin_copysign(t *TLS, x, y float64) float64 {
|
|
return Xcopysign(t, x, y)
|
|
}
|
|
|
|
func X__builtin_copysignf(t *TLS, x, y float32) float32 {
|
|
return Xcopysignf(t, x, y)
|
|
}
|
|
|
|
func X__builtin_copysignl(t *TLS, x, y float64) float64 {
|
|
return Xcopysign(t, x, y)
|
|
}
|
|
|
|
func X__builtin_exit(t *TLS, status int32) {
|
|
Xexit(t, status)
|
|
}
|
|
|
|
func X__builtin_fabs(t *TLS, x float64) float64 {
|
|
return Xfabs(t, x)
|
|
}
|
|
|
|
func X__builtin_fabsf(t *TLS, x float32) float32 {
|
|
return Xfabsf(t, x)
|
|
}
|
|
|
|
func X__builtin_free(t *TLS, ptr uintptr) {
|
|
Xfree(t, ptr)
|
|
}
|
|
|
|
func X__builtin_huge_val(t *TLS) float64 {
|
|
return math.Inf(1)
|
|
}
|
|
|
|
func X__builtin_huge_valf(t *TLS) float32 {
|
|
return float32(math.Inf(1))
|
|
}
|
|
|
|
func X__builtin_inf(t *TLS) float64 {
|
|
return math.Inf(1)
|
|
}
|
|
|
|
func X__builtin_infl(t *TLS) float64 {
|
|
return math.Inf(1)
|
|
}
|
|
|
|
func X__builtin_malloc(t *TLS, size Tsize_t) uintptr {
|
|
return Xmalloc(t, size)
|
|
}
|
|
|
|
func X__builtin_memcmp(t *TLS, s1, s2 uintptr, n Tsize_t) int32 {
|
|
return Xmemcmp(t, s1, s2, n)
|
|
}
|
|
|
|
func X__builtin_nan(t *TLS, s uintptr) float64 {
|
|
return math.NaN()
|
|
}
|
|
|
|
func X__builtin_nanl(t *TLS, s uintptr) float64 {
|
|
return math.NaN()
|
|
}
|
|
|
|
func X__builtin_prefetch(t *TLS, addr, args uintptr) {
|
|
}
|
|
|
|
func X__builtin_strchr(t *TLS, s uintptr, c int32) uintptr {
|
|
return Xstrchr(t, s, c)
|
|
}
|
|
|
|
func X__builtin_strcmp(t *TLS, s1, s2 uintptr) int32 {
|
|
return Xstrcmp(t, s1, s2)
|
|
}
|
|
|
|
func X__builtin_strcpy(t *TLS, dest, src uintptr) uintptr {
|
|
return Xstrcpy(t, dest, src)
|
|
}
|
|
|
|
func X__builtin_strlen(t *TLS, s uintptr) Tsize_t {
|
|
return Xstrlen(t, s)
|
|
}
|
|
|
|
func X__builtin_trap(t *TLS) {
|
|
Xabort(t)
|
|
}
|
|
|
|
func X__builtin_popcount(t *TLS, x uint32) int32 {
|
|
return int32(mbits.OnesCount32(x))
|
|
}
|
|
|
|
// int __builtin_popcountl (unsigned long x)
|
|
func X__builtin_popcountl(t *TLS, x ulong) int32 {
|
|
return int32(mbits.OnesCount32(x))
|
|
}
|
|
|
|
// char * __builtin___strcpy_chk (char *dest, const char *src, size_t os);
|
|
func X__builtin___strcpy_chk(t *TLS, dest, src uintptr, os Tsize_t) uintptr {
|
|
return Xstrcpy(t, dest, src)
|
|
}
|
|
|
|
// uint16_t __builtin_bswap16 (uint32_t x)
|
|
func X__builtin_bswap16(t *TLS, x uint16) uint16 {
|
|
return x<<8 |
|
|
x>>8
|
|
}
|
|
|
|
// uint32_t __builtin_bswap32 (uint32_t x)
|
|
func X__builtin_bswap32(t *TLS, x uint32) uint32 {
|
|
return x<<24 |
|
|
x&0xff00<<8 |
|
|
x&0xff0000>>8 |
|
|
x>>24
|
|
}
|
|
|
|
// uint64_t __builtin_bswap64 (uint64_t x)
|
|
func X__builtin_bswap64(t *TLS, x uint64) uint64 {
|
|
return x<<56 |
|
|
x&0xff00<<40 |
|
|
x&0xff0000<<24 |
|
|
x&0xff000000<<8 |
|
|
x&0xff00000000>>8 |
|
|
x&0xff0000000000>>24 |
|
|
x&0xff000000000000>>40 |
|
|
x>>56
|
|
}
|
|
|
|
// bool __builtin_add_overflow (type1 a, type2 b, type3 *res)
|
|
func X__builtin_add_overflowInt64(t *TLS, a, b int64, res uintptr) int32 {
|
|
r, ovf := mathutil.AddOverflowInt64(a, b)
|
|
*(*int64)(unsafe.Pointer(res)) = r
|
|
return Bool32(ovf)
|
|
}
|
|
|
|
// bool __builtin_add_overflow (type1 a, type2 b, type3 *res)
|
|
func X__builtin_add_overflowUint32(t *TLS, a, b uint32, res uintptr) int32 {
|
|
r := a + b
|
|
*(*uint32)(unsafe.Pointer(res)) = r
|
|
return Bool32(r < a)
|
|
}
|
|
|
|
// bool __builtin_add_overflow (type1 a, type2 b, type3 *res)
|
|
func X__builtin_add_overflowUint64(t *TLS, a, b uint64, res uintptr) int32 {
|
|
r := a + b
|
|
*(*uint64)(unsafe.Pointer(res)) = r
|
|
return Bool32(r < a)
|
|
}
|
|
|
|
// bool __builtin_sub_overflow (type1 a, type2 b, type3 *res)
|
|
func X__builtin_sub_overflowInt64(t *TLS, a, b int64, res uintptr) int32 {
|
|
r, ovf := mathutil.SubOverflowInt64(a, b)
|
|
*(*int64)(unsafe.Pointer(res)) = r
|
|
return Bool32(ovf)
|
|
}
|
|
|
|
// bool __builtin_mul_overflow (type1 a, type2 b, type3 *res)
|
|
func X__builtin_mul_overflowInt64(t *TLS, a, b int64, res uintptr) int32 {
|
|
r, ovf := mathutil.MulOverflowInt64(a, b)
|
|
*(*int64)(unsafe.Pointer(res)) = r
|
|
return Bool32(ovf)
|
|
}
|
|
|
|
// bool __builtin_mul_overflow (type1 a, type2 b, type3 *res)
|
|
func X__builtin_mul_overflowUint64(t *TLS, a, b uint64, res uintptr) int32 {
|
|
hi, lo := mbits.Mul64(a, b)
|
|
*(*uint64)(unsafe.Pointer(res)) = lo
|
|
return Bool32(hi != 0)
|
|
}
|
|
|
|
// bool __builtin_mul_overflow (type1 a, type2 b, type3 *res)
|
|
func X__builtin_mul_overflowUint128(t *TLS, a, b Uint128, res uintptr) int32 {
|
|
r, ovf := a.mulOvf(b)
|
|
*(*Uint128)(unsafe.Pointer(res)) = r
|
|
return Bool32(ovf)
|
|
}
|
|
|
|
func X__builtin_unreachable(t *TLS) {
|
|
fmt.Fprintf(os.Stderr, "unrechable\n")
|
|
os.Stderr.Sync()
|
|
Xexit(t, 1)
|
|
}
|
|
|
|
func X__builtin_sprintf(t *TLS, str, format, args uintptr) (r int32) {
|
|
return Xsprintf(t, str, format, args)
|
|
}
|
|
|
|
func X__builtin_memcpy(t *TLS, dest, src uintptr, n Tsize_t) (r uintptr) {
|
|
return Xmemcpy(t, dest, src, n)
|
|
}
|
|
|
|
// void * __builtin___memcpy_chk (void *dest, const void *src, size_t n, size_t os);
|
|
func X__builtin___memcpy_chk(t *TLS, dest, src uintptr, n, os Tsize_t) (r uintptr) {
|
|
if os != ^Tsize_t(0) && n < os {
|
|
Xabort(t)
|
|
}
|
|
|
|
return Xmemcpy(t, dest, src, n)
|
|
}
|
|
|
|
func X__builtin_memset(t *TLS, s uintptr, c int32, n Tsize_t) uintptr {
|
|
return Xmemset(t, s, c, n)
|
|
}
|
|
|
|
// void * __builtin___memset_chk (void *s, int c, size_t n, size_t os);
|
|
func X__builtin___memset_chk(t *TLS, s uintptr, c int32, n, os Tsize_t) uintptr {
|
|
if os < n {
|
|
Xabort(t)
|
|
}
|
|
|
|
return Xmemset(t, s, c, n)
|
|
}
|
|
|
|
// size_t __builtin_object_size (const void * ptr, int type)
|
|
func X__builtin_object_size(t *TLS, p uintptr, typ int32) Tsize_t {
|
|
return ^Tsize_t(0) //TODO frontend magic
|
|
}
|
|
|
|
// int __builtin___sprintf_chk (char *s, int flag, size_t os, const char *fmt, ...);
|
|
func X__builtin___sprintf_chk(t *TLS, s uintptr, flag int32, os Tsize_t, format, args uintptr) (r int32) {
|
|
return Xsprintf(t, s, format, args)
|
|
}
|
|
|
|
func X__builtin_isnan(t *TLS, x float64) int32 {
|
|
return Bool32(math.IsNaN(x))
|
|
}
|
|
|
|
func X__builtin_isnanf(t *TLS, x float32) int32 {
|
|
return Bool32(math.IsNaN(float64(x)))
|
|
}
|
|
|
|
func X__isnanl(t *TLS, arg float64) int32 {
|
|
return X__builtin_isnanl(t, arg)
|
|
}
|
|
|
|
func X__builtin_isnanl(t *TLS, x float64) int32 {
|
|
return Bool32(math.IsNaN(x))
|
|
}
|
|
|
|
func X__builtin_log2(t *TLS, x float64) float64 {
|
|
return Xlog2(t, x)
|
|
}
|
|
|
|
func X__builtin___strncpy_chk(t *TLS, dest, src uintptr, n, os Tsize_t) (r uintptr) {
|
|
if n != ^Tsize_t(0) && os < n {
|
|
Xabort(t)
|
|
}
|
|
|
|
return Xstrncpy(t, dest, src, n)
|
|
}
|
|
|
|
func X__builtin___strcat_chk(t *TLS, dest, src uintptr, os Tsize_t) (r uintptr) {
|
|
return Xstrcat(t, dest, src)
|
|
}
|
|
|
|
func X__builtin___memmove_chk(t *TLS, dest, src uintptr, n, os Tsize_t) uintptr {
|
|
if os != ^Tsize_t(0) && os < n {
|
|
Xabort(t)
|
|
}
|
|
|
|
return Xmemmove(t, dest, src, n)
|
|
}
|
|
|
|
func X__builtin_isunordered(t *TLS, a, b float64) int32 {
|
|
return Bool32(math.IsNaN(a) || math.IsNaN(b))
|
|
}
|
|
|
|
func X__builtin_rintf(tls *TLS, x float32) (r float32) {
|
|
return Xrintf(tls, x)
|
|
}
|
|
|
|
func X__builtin_lrintf(tls *TLS, x float32) (r long) {
|
|
return Xlrintf(tls, x)
|
|
}
|
|
|
|
func X__builtin_lrint(tls *TLS, x float64) (r long) {
|
|
return Xlrint(tls, x)
|
|
}
|
|
|
|
// double __builtin_fma(double x, double y, double z);
|
|
func X__builtin_fma(tls *TLS, x, y, z float64) (r float64) {
|
|
return math.FMA(x, y, z)
|
|
}
|
|
|
|
func X__builtin_isprint(tls *TLS, c int32) (r int32) {
|
|
return Xisprint(tls, c)
|
|
}
|
|
|
|
func X__builtin_trunc(tls *TLS, x float64) (r float64) {
|
|
return Xtrunc(tls, x)
|
|
}
|
|
|
|
func X__builtin_hypot(tls *TLS, x float64, y float64) (r float64) {
|
|
return Xhypot(tls, x, y)
|
|
}
|
|
|
|
func X__builtin_vsnprintf(t *TLS, str uintptr, size Tsize_t, format, va uintptr) int32 {
|
|
return Xsnprintf(t, str, size, format, va)
|
|
}
|
|
|
|
func X__mingw_vsnprintf(tls *TLS, str uintptr, size Tsize_t, format, va uintptr) int32 {
|
|
return Xsnprintf(tls, str, size, format, va)
|
|
}
|
|
|
|
func X__ms_vsnprintf(tls *TLS, str uintptr, size Tsize_t, format, va uintptr) int32 {
|
|
return Xsnprintf(tls, str, size, format, va)
|
|
}
|
|
|
|
func X_vsnprintf(tls *TLS, str uintptr, size Tsize_t, format, va uintptr) int32 {
|
|
return Xsnprintf(tls, str, size, format, va)
|
|
}
|
|
|
|
// int snprintf(char *str, size_t size, const char *format, ...);
|
|
func Xsnprintf(t *TLS, str uintptr, size Tsize_t, format, args uintptr) (r int32) {
|
|
if __ccgo_strace {
|
|
trc("t=%v str=%v size=%v args=%v, (%v:)", t, str, size, args, origin(2))
|
|
defer func() { trc("-> %v", r) }()
|
|
}
|
|
if format == 0 {
|
|
return 0
|
|
}
|
|
|
|
b := printf(format, args)
|
|
r = int32(len(b))
|
|
if size == 0 {
|
|
return r
|
|
}
|
|
|
|
if len(b)+1 > int(size) {
|
|
b = b[:size-1]
|
|
}
|
|
n := len(b)
|
|
copy(unsafe.Slice((*byte)(unsafe.Pointer(str)), n)[:n:n], b)
|
|
*(*byte)(unsafe.Pointer(str + uintptr(n))) = 0
|
|
return r
|
|
}
|
|
|
|
var proc_open = dll.NewProc("_open")
|
|
var _ = proc_open.Addr()
|
|
|
|
// int open(const char * __filename, int __flags, ...)
|
|
func X_open(tls *TLS, filename uintptr, flags int32, va uintptr) (r int32) {
|
|
var mode int32
|
|
if va != 0 {
|
|
mode = VaInt32(&va)
|
|
}
|
|
if __ccgo_strace {
|
|
trc("filename=%q flags=%v mode=%#0o", GoString(filename), flags, mode)
|
|
defer func() { trc(`X_open->%+v`, r) }()
|
|
}
|
|
r0, r1, err := syscall.SyscallN(proc_open.Addr(), filename, uintptr(flags), uintptr(mode))
|
|
_, _ = r0, r1
|
|
if err != 0 {
|
|
tls.setErrno(int32(err))
|
|
}
|
|
return int32(r0)
|
|
}
|
|
|
|
func Xopen(tls *TLS, filename uintptr, flags int32, va uintptr) int32 {
|
|
return X_open(tls, filename, flags, va)
|
|
}
|
|
|
|
// This version does include the zero terminator in the returned Go string.
|
|
func goWideString(p uintptr) string {
|
|
if p == 0 {
|
|
return ""
|
|
}
|
|
var w []uint16
|
|
for {
|
|
wc := *(*uint16)(unsafe.Pointer(p))
|
|
p += 2
|
|
w = append(w, wc)
|
|
// append until U0000
|
|
if wc == 0 {
|
|
break
|
|
}
|
|
}
|
|
s := utf16.Decode(w)
|
|
return string(s)
|
|
}
|
|
|
|
var proc_wopen = dll.NewProc("_wopen")
|
|
var _ = proc_wopen.Addr()
|
|
|
|
// int wopen(wchar * __filename, int __flags, ...)
|
|
func X_wopen(tls *TLS, filename uintptr, flags int32, va uintptr) (r int32) {
|
|
var mode int32
|
|
if va != 0 {
|
|
mode = VaInt32(&va)
|
|
}
|
|
if __ccgo_strace {
|
|
trc("filename=%q flags=%v mode=%#0o", goWideString(filename), flags, mode)
|
|
defer func() { trc(`X_wopen->%+v`, r) }()
|
|
}
|
|
r0, r1, err := syscall.SyscallN(proc_wopen.Addr(), filename, uintptr(flags), uintptr(mode))
|
|
_, _ = r0, r1
|
|
if err != 0 {
|
|
tls.setErrno(int32(err))
|
|
}
|
|
return int32(r0)
|
|
}
|
|
|
|
func Xwopen(tls *TLS, filename uintptr, flags int32, va uintptr) int32 {
|
|
return X_wopen(tls, filename, flags, va)
|
|
}
|
|
|
|
func Xread(tls *TLS, __FileHandle int32, __DstBuf uintptr, __MaxCharCount uint32) (r int32) {
|
|
return X_read(tls, __FileHandle, __DstBuf, __MaxCharCount)
|
|
}
|
|
|
|
func Xclose(tls *TLS, __FileHandle int32) (r int32) {
|
|
return X_close(tls, __FileHandle)
|
|
}
|
|
|
|
func Xwrite(tls *TLS, __FileHandle int32, __Buf uintptr, __MaxCharCount uint32) (r int32) {
|
|
return X_write(tls, __FileHandle, __Buf, __MaxCharCount)
|
|
}
|
|
|
|
func Xunlink(tls *TLS, __Filename uintptr) (r int32) {
|
|
return X_unlink(tls, __Filename)
|
|
}
|
|
|
|
func Xsetmode(tls *TLS, __FileHandle int32, __Mode int32) (r int32) {
|
|
return X_setmode(tls, __FileHandle, __Mode)
|
|
}
|
|
|
|
func Xfileno(tls *TLS, __File uintptr) (r int32) {
|
|
return X_fileno(tls, __File)
|
|
}
|
|
|
|
// void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
|
|
func Xqsort(tls *TLS, base uintptr, nmemb, size Tsize_t, compar uintptr) {
|
|
sort.Sort(&sorter{
|
|
len: int(nmemb),
|
|
base: base,
|
|
sz: uintptr(size),
|
|
f: (*struct {
|
|
f func(*TLS, uintptr, uintptr) int32
|
|
})(unsafe.Pointer(&struct{ uintptr }{compar})).f,
|
|
t: tls,
|
|
})
|
|
}
|
|
|
|
func Xprintf(tls *TLS, format, va uintptr) int32 {
|
|
b := printf(format, va)
|
|
if len(b) == 0 {
|
|
return 0
|
|
}
|
|
|
|
n, err := fwrite(tls, Xstdout, printf(format, va))
|
|
if err != nil {
|
|
return -1
|
|
}
|
|
|
|
return int32(n)
|
|
}
|
|
|
|
//UCRT // int __attribute__((__cdecl__)) putchar(int _Ch);
|
|
//UCRT func Xputchar(tls *TLS, __Ch int32) (r int32) {
|
|
//UCRT return Xputc(tls, __Ch, Xstdout)
|
|
//UCRT }
|
|
|
|
//UCRT // int __attribute__((__cdecl__)) puts(const char *_Str);
|
|
//UCRT func Xputs(tls *TLS, __Str uintptr) (r int32) {
|
|
//UCRT r = Xfputs(tls, __Str, Xstdout)
|
|
//UCRT return r + Xputc(tls, '\n', Xstdout)
|
|
//UCRT }
|
|
|
|
func Xtzset(tls *TLS) {
|
|
X_tzset(tls)
|
|
}
|
|
|
|
func GoWideString(p uintptr) string {
|
|
return goWideStringNZ(p)
|
|
}
|
|
|
|
func goWideStringNZ(p uintptr) string {
|
|
if p == 0 {
|
|
return ""
|
|
}
|
|
|
|
var w []uint16
|
|
for {
|
|
wc := *(*uint16)(unsafe.Pointer(p))
|
|
p += 2
|
|
if wc == 0 {
|
|
break
|
|
}
|
|
|
|
w = append(w, wc)
|
|
}
|
|
s := utf16.Decode(w)
|
|
return string(s)
|
|
}
|
|
|
|
func X_wgetenv(t *TLS, varname uintptr) uintptr {
|
|
if wenvValid.Swap(true) == false {
|
|
bootWinEnviron(t)
|
|
}
|
|
k := strings.ToLower(goWideStringNZ(varname))
|
|
for _, v := range winEnviron[:len(winEnviron)-1] {
|
|
s := strings.ToLower(goWideStringNZ(v))
|
|
x := strings.IndexByte(s, '=')
|
|
if s[:x] == k {
|
|
return v
|
|
}
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func allocW(t *TLS, v string) (r uintptr) {
|
|
s := utf16.Encode([]rune(v))
|
|
p := Xcalloc(t, Tsize_t(len(s)+1), 2)
|
|
if p == 0 {
|
|
panic(todo(""))
|
|
}
|
|
|
|
r = p
|
|
for _, v := range s {
|
|
*(*uint16)(unsafe.Pointer(p)) = v
|
|
p += 2
|
|
}
|
|
return r
|
|
}
|
|
|
|
func X_wputenv(t *TLS, envstring uintptr) int32 {
|
|
if wenvValid.Swap(true) == false {
|
|
bootWinEnviron(t)
|
|
}
|
|
s0 := goWideStringNZ(envstring)
|
|
s := strings.ToLower(s0)
|
|
x := strings.IndexByte(s, '=')
|
|
k := s[:x]
|
|
for i, v := range winEnviron[:len(winEnviron)-1] {
|
|
s2 := strings.ToLower(goWideStringNZ(v))
|
|
x := strings.IndexByte(s2, '=')
|
|
if s2[:x] == k {
|
|
Xfree(t, v)
|
|
winEnviron[i] = allocW(t, s0)
|
|
return 0
|
|
}
|
|
}
|
|
|
|
np := allocW(t, s0)
|
|
winEnviron = winEnviron[:len(winEnviron)-1]
|
|
winEnviron = append(winEnviron, np, 0)
|
|
wenviron = uintptr(unsafe.Pointer(&winEnviron[0]))
|
|
return 0
|
|
}
|
|
|
|
func bootWinEnviron(t *TLS) {
|
|
winEnviron = winEnviron[:0]
|
|
for _, s := range os.Environ() {
|
|
r := allocW(t, s)
|
|
winEnviron = append(winEnviron, r)
|
|
}
|
|
wenviron = uintptr(unsafe.Pointer(&winEnviron[0]))
|
|
}
|
|
|
|
func X_copysign(t *TLS, x, y float64) float64 {
|
|
return Xcopysign(t, x, y)
|
|
}
|
|
|
|
func Xchmod(tls *TLS, __Filename uintptr, __Mode int32) (r int32) {
|
|
return X_chmod(tls, __Filename, __Mode)
|
|
}
|
|
|
|
func Xisatty(tls *TLS, __FileHandle int32) (r int32) {
|
|
return X_isatty(tls, __FileHandle)
|
|
}
|
|
|
|
func AtomicLoadNUint8(ptr uintptr, memorder int32) uint8 {
|
|
return byte(a_load_8(ptr))
|
|
}
|
|
|
|
func AtomicLoadNUint16(ptr uintptr, memorder int32) uint16 {
|
|
return uint16(a_load_16(ptr))
|
|
}
|
|
|
|
func AtomicStoreNUint8(ptr uintptr, val uint8, memorder int32) {
|
|
a_store_8(ptr, byte(val))
|
|
}
|
|
|
|
func AtomicStoreNUint16(ptr uintptr, val uint16, memorder int32) {
|
|
a_store_16(ptr, val)
|
|
}
|
|
|
|
func AtomicLoadPInt32(addr uintptr) (val int32) {
|
|
return atomic.LoadInt32((*int32)(unsafe.Pointer(addr)))
|
|
}
|
|
|
|
func AtomicLoadPInt64(addr uintptr) (val int64) {
|
|
return atomic.LoadInt64((*int64)(unsafe.Pointer(addr)))
|
|
}
|
|
|
|
func AtomicLoadPUint32(addr uintptr) (val uint32) {
|
|
return atomic.LoadUint32((*uint32)(unsafe.Pointer(addr)))
|
|
}
|
|
|
|
func AtomicLoadPUint64(addr uintptr) (val uint64) {
|
|
return atomic.LoadUint64((*uint64)(unsafe.Pointer(addr)))
|
|
}
|
|
|
|
func AtomicLoadPUintptr(addr uintptr) (val uintptr) {
|
|
return atomic.LoadUintptr((*uintptr)(unsafe.Pointer(addr)))
|
|
}
|
|
|
|
func AtomicLoadPFloat32(addr uintptr) (val float32) {
|
|
return math.Float32frombits(atomic.LoadUint32((*uint32)(unsafe.Pointer(addr))))
|
|
}
|
|
|
|
func AtomicLoadPFloat64(addr uintptr) (val float64) {
|
|
return math.Float64frombits(atomic.LoadUint64((*uint64)(unsafe.Pointer(addr))))
|
|
}
|
|
|
|
func AtomicStorePInt32(addr uintptr, val int32) {
|
|
atomic.StoreInt32((*int32)(unsafe.Pointer(addr)), val)
|
|
}
|
|
|
|
func AtomicStorePInt64(addr uintptr, val int64) {
|
|
atomic.StoreInt64((*int64)(unsafe.Pointer(addr)), val)
|
|
}
|
|
|
|
func AtomicStorePUint32(addr uintptr, val uint32) {
|
|
atomic.StoreUint32((*uint32)(unsafe.Pointer(addr)), val)
|
|
}
|
|
|
|
func AtomicStorePUint64(addr uintptr, val uint64) {
|
|
atomic.StoreUint64((*uint64)(unsafe.Pointer(addr)), val)
|
|
}
|
|
|
|
func AtomicStorePUintptr(addr uintptr, val uintptr) {
|
|
atomic.StoreUintptr((*uintptr)(unsafe.Pointer(addr)), val)
|
|
}
|
|
|
|
func AtomicStorePFloat32(addr uintptr, val float32) {
|
|
atomic.StoreUint32((*uint32)(unsafe.Pointer(addr)), math.Float32bits(val))
|
|
}
|
|
|
|
func AtomicStorePFloat64(addr uintptr, val float64) {
|
|
atomic.StoreUint64((*uint64)(unsafe.Pointer(addr)), math.Float64bits(val))
|
|
}
|
|
|
|
// int _snwprintf(
|
|
//
|
|
// wchar_t *buffer,
|
|
// size_t count,
|
|
// const wchar_t *format [,
|
|
// argument] ...
|
|
//
|
|
// );
|
|
func X_snwprintf(tls *TLS, buffer uintptr, count Tsize_t, format, va uintptr) int32 {
|
|
panic(todo(""))
|
|
}
|
|
|
|
func Xsnwprintf(tls *TLS, buffer uintptr, count Tsize_t, format, va uintptr) int32 {
|
|
return X_snwprintf(tls, buffer, count, format, va)
|
|
}
|
|
|
|
// int _vscprintf(const char *format, va_list va);
|
|
func X_vscprintf(t *TLS, format uintptr, va uintptr) int32 {
|
|
return int32(len(printf(format, va)))
|
|
}
|
|
|
|
func X_sscanf(t *TLS, str, format, va uintptr) int32 {
|
|
return scanf(strings.NewReader(GoString(str)), format, va)
|
|
}
|
|
|
|
// int sscanf(const char *str, const char *format, ...);
|
|
func Xsscanf(t *TLS, str, format, va uintptr) int32 {
|
|
return X_sscanf(t, str, format, va)
|
|
}
|
|
|
|
// pid_t getpid(void);
|
|
func Xgetpid(t *TLS) int32 {
|
|
return int32(os.Getpid())
|
|
}
|
|
|
|
// void __assert_fail(const char * assertion, const char * file, unsigned int line, const char * function);
|
|
func X__assert_fail(t *TLS, assertion, file uintptr, line uint32, function uintptr) {
|
|
if __ccgo_strace {
|
|
trc("t=%v file=%v line=%v function=%v, (%v:)", t, file, line, function, origin(2))
|
|
}
|
|
fmt.Fprintf(os.Stderr, "assertion failure: %s:%d.%s: %s\n", GoString(file), line, GoString(function), GoString(assertion))
|
|
os.Stderr.Sync()
|
|
Xexit(t, 1)
|
|
}
|
|
|
|
// unsigned long long strtoull(const char *nptr, char **endptr, int base);
|
|
//UCRT func Xstrtoull(t *TLS, nptr, endptr uintptr, base int32) uint64 {
|
|
//UCRT var s uintptr = nptr
|
|
//UCRT var acc uint64
|
|
//UCRT var c byte
|
|
//UCRT var cutoff uint64
|
|
//UCRT var neg int32
|
|
//UCRT var any int32
|
|
//UCRT var cutlim int32
|
|
//UCRT
|
|
//UCRT /*
|
|
//UCRT * Skip white space and pick up leading +/- sign if any.
|
|
//UCRT * If base is 0, allow 0x for hex and 0 for octal, else
|
|
//UCRT * assume decimal; if base is already 16, allow 0x.
|
|
//UCRT */
|
|
//UCRT for {
|
|
//UCRT c = *(*byte)(unsafe.Pointer(s))
|
|
//UCRT PostIncUintptr(&s, 1)
|
|
//UCRT var sp = strings.TrimSpace(string(c))
|
|
//UCRT if len(sp) > 0 {
|
|
//UCRT break
|
|
//UCRT }
|
|
//UCRT }
|
|
//UCRT
|
|
//UCRT if c == '-' {
|
|
//UCRT neg = 1
|
|
//UCRT c = *(*byte)(unsafe.Pointer(s))
|
|
//UCRT PostIncUintptr(&s, 1)
|
|
//UCRT } else if c == '+' {
|
|
//UCRT c = *(*byte)(unsafe.Pointer(s))
|
|
//UCRT PostIncUintptr(&s, 1)
|
|
//UCRT }
|
|
//UCRT
|
|
//UCRT sp := *(*byte)(unsafe.Pointer(s))
|
|
//UCRT
|
|
//UCRT if (base == 0 || base == 16) &&
|
|
//UCRT c == '0' && (sp == 'x' || sp == 'X') {
|
|
//UCRT PostIncUintptr(&s, 1)
|
|
//UCRT c = *(*byte)(unsafe.Pointer(s)) //s[1];
|
|
//UCRT PostIncUintptr(&s, 1)
|
|
//UCRT base = 16
|
|
//UCRT }
|
|
//UCRT if base == 0 {
|
|
//UCRT if c == '0' {
|
|
//UCRT base = 0
|
|
//UCRT } else {
|
|
//UCRT base = 10
|
|
//UCRT }
|
|
//UCRT }
|
|
//UCRT
|
|
//UCRT cutoff = math.MaxUint64 / uint64(base)
|
|
//UCRT cutlim = int32(math.MaxUint64 % uint64(base))
|
|
//UCRT
|
|
//UCRT acc = 0
|
|
//UCRT any = 0
|
|
//UCRT
|
|
//UCRT for {
|
|
//UCRT var cs = string(c)
|
|
//UCRT if unicode.IsDigit([]rune(cs)[0]) {
|
|
//UCRT c -= '0'
|
|
//UCRT } else if unicode.IsLetter([]rune(cs)[0]) {
|
|
//UCRT if unicode.IsUpper([]rune(cs)[0]) {
|
|
//UCRT c -= 'A' - 10
|
|
//UCRT } else {
|
|
//UCRT c -= 'a' - 10
|
|
//UCRT }
|
|
//UCRT } else {
|
|
//UCRT break
|
|
//UCRT }
|
|
//UCRT
|
|
//UCRT if int32(c) >= base {
|
|
//UCRT break
|
|
//UCRT }
|
|
//UCRT if any < 0 || acc > cutoff || (acc == cutoff && int32(c) > cutlim) {
|
|
//UCRT any = -1
|
|
//UCRT
|
|
//UCRT } else {
|
|
//UCRT any = 1
|
|
//UCRT acc *= uint64(base)
|
|
//UCRT acc += uint64(c)
|
|
//UCRT }
|
|
//UCRT
|
|
//UCRT c = *(*byte)(unsafe.Pointer(s))
|
|
//UCRT PostIncUintptr(&s, 1)
|
|
//UCRT }
|
|
//UCRT
|
|
//UCRT if any < 0 {
|
|
//UCRT acc = math.MaxUint64
|
|
//UCRT t.setErrno(ERANGE)
|
|
//UCRT } else if neg == 1 {
|
|
//UCRT acc = -acc
|
|
//UCRT }
|
|
//UCRT
|
|
//UCRT if endptr != 0 {
|
|
//UCRT if any == 1 {
|
|
//UCRT PostDecUintptr(&s, 1)
|
|
//UCRT AssignPtrUintptr(endptr, s)
|
|
//UCRT } else {
|
|
//UCRT AssignPtrUintptr(endptr, nptr)
|
|
//UCRT }
|
|
//UCRT }
|
|
//UCRT return acc
|
|
//UCRT }
|
|
|
|
// int _stat32i64(const char *path, struct _stat32i64 *buffer);
|
|
//UCRT func X_stat64i32(t *TLS, path uintptr, buffer uintptr) int32 {
|
|
//UCRT panic(todo(""))
|
|
//UCRT }
|
|
|
|
func X__mingw_strtod(t *TLS, s uintptr, p uintptr) float64 {
|
|
return Xstrtod(t, s, p)
|
|
}
|
|
|
|
// int vsscanf(const char *str, const char *format, va_list ap);
|
|
func X__ms_vsscanf(t *TLS, str, format, ap uintptr) int32 {
|
|
panic(todo(""))
|
|
}
|
|
|
|
// int vsscanf(const char *str, const char *format, va_list ap);
|
|
func X__mingw_vsscanf(t *TLS, str, format, ap uintptr) int32 {
|
|
return Xsscanf(t, str, format, ap)
|
|
}
|
|
|
|
// unsigned int _set_abort_behavior(
|
|
//
|
|
// unsigned int flags,
|
|
// unsigned int mask
|
|
//
|
|
// );
|
|
//UCRT func X_set_abort_behavior(t *TLS, _ ...interface{}) uint32 {
|
|
//UCRT panic(todo(""))
|
|
//UCRT }
|
|
|
|
// double atof(const char *nptr);
|
|
func Xatof(t *TLS, nptr uintptr) float64 {
|
|
n, _ := strconv.ParseFloat(GoString(nptr), 64)
|
|
return n
|
|
}
|
|
|
|
func X__builtin_snprintf(t *TLS, str uintptr, size Tsize_t, format, args uintptr) int32 {
|
|
return Xsnprintf(t, str, size, format, args)
|
|
}
|
|
|
|
// int _snprintf(char *str, size_t size, const char *format, ...);
|
|
func X_snprintf(t *TLS, str uintptr, size Tsize_t, format, args uintptr) int32 {
|
|
return Xsnprintf(t, str, size, format, args)
|
|
}
|
|
|
|
// intptr_t _findfirst64i32(const char *filespec, struct _finddata64i32_t *fileinfo);
|
|
//UCRT func X_findfirst64i32(t *TLS, filespec, fileinfo uintptr) Tintptr_t {
|
|
//UCRT panic(todo(""))
|
|
//UCRT }
|
|
|
|
// int _findnext64i32(intptr_t handle, struct _finddata64i32_t *fileinfo);
|
|
//UCRT func X_findnext64i32(t *TLS, handle Tintptr_t, fileinfo uintptr) int32 {
|
|
//UCRT panic(todo(""))
|
|
//UCRT }
|
|
|
|
func X__isnan(t *TLS, x float64) int32 {
|
|
return Bool32(math.IsNaN(x))
|
|
}
|
|
|
|
// int _stati64(char *path, struct _stati64 *buffer);
|
|
func X_stati64(t *TLS, path, buffer uintptr) int32 {
|
|
return X_stat64(t, path, buffer)
|
|
}
|
|
|
|
// int _fstati64(int fd, struct _stati64 *buffer);
|
|
func X_fstati64(t *TLS, fd int32, buffer uintptr) int32 {
|
|
return X_fstat64(t, fd, buffer)
|
|
}
|
|
|
|
func X_strcmpi(tls *TLS, __Str1 uintptr, __Str2 uintptr) (r int32) {
|
|
if __ccgo_strace {
|
|
trc("_Str1=%+v _Str2=%+v", __Str1, __Str2)
|
|
defer func() { trc(`X_strcmpi->%+v`, r) }()
|
|
}
|
|
r0, r1, err := syscall.SyscallN(proc_stricmp.Addr(), __Str1, __Str2)
|
|
if err != 0 {
|
|
if __ccgo_strace {
|
|
trc(`r0=%v r1=%v err=%v`, r0, r1, err)
|
|
}
|
|
tls.setErrno(int32(err))
|
|
}
|
|
return int32(r0)
|
|
}
|
|
|
|
// ------------------------------------------------------------------------ (A)
|
|
// https://chromium.googlesource.com/external/github.com/kripken/emscripten/+/refs/tags/1.2.9/system/lib/libc/stdlib/strtod.c
|
|
//
|
|
// /*
|
|
// * strtod.c --
|
|
// *
|
|
// * Source code for the "strtod" library procedure.
|
|
// *
|
|
// * Copyright (c) 1988-1993 The Regents of the University of California.
|
|
// * Copyright (c) 1994 Sun Microsystems, Inc.
|
|
// *
|
|
// * Permission to use, copy, modify, and distribute this
|
|
// * software and its documentation for any purpose and without
|
|
// * fee is hereby granted, provided that the above copyright
|
|
// * notice appear in all copies. The University of California
|
|
// * makes no representations about the suitability of this
|
|
// * software for any purpose. It is provided "as is" without
|
|
// * express or implied warranty.
|
|
// *
|
|
// * RCS: @(#) $Id$
|
|
// *
|
|
// * Taken from http://svn.ruby-lang.org/repos/ruby/branches/ruby_1_8/missing/strtod.c
|
|
// */
|
|
//
|
|
// C documentation
|
|
//
|
|
// /*
|
|
// *----------------------------------------------------------------------
|
|
// *
|
|
// * strtod --
|
|
// *
|
|
// * This procedure converts a floating-point number from an ASCII
|
|
// * decimal representation to internal double-precision format.
|
|
// *
|
|
// * Results:
|
|
// * The return value is the double-precision floating-point
|
|
// * representation of the characters in string. If endPtr isn't
|
|
// * NULL, then *endPtr is filled in with the address of the
|
|
// * next character after the last one that was part of the
|
|
// * floating-point number.
|
|
// *
|
|
// * Side effects:
|
|
// * None.
|
|
// *
|
|
// *----------------------------------------------------------------------
|
|
// */
|
|
func Xstrtod(tls *TLS, string1 uintptr, endPtr uintptr) (r float64) {
|
|
/* If non-NULL, store terminating character's
|
|
* address here. */
|
|
var c, decPt, exp, expSign, frac1, frac2, fracExp, mantSize, sign, v1, v2 int32
|
|
var d, p, pExp uintptr
|
|
var dblExp, fraction float64
|
|
_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ = c, d, dblExp, decPt, exp, expSign, frac1, frac2, fracExp, fraction, mantSize, p, pExp, sign, v1, v2
|
|
expSign = FALSE
|
|
exp = 0 /* Exponent read from "EX" field. */
|
|
fracExp = 0 /* Temporarily holds location of exponent
|
|
* in string. */
|
|
/*
|
|
* Strip off leading blanks and check for a sign.
|
|
*/
|
|
p = string1
|
|
for {
|
|
v1 = int32(*(*int8)(unsafe.Pointer(p)))
|
|
v2 = BoolInt32(v1 == int32(' ') || uint32(v1)-uint32('\t') < uint32(5))
|
|
goto _3
|
|
_3:
|
|
if !(v2 != 0) {
|
|
break
|
|
}
|
|
p += uintptr(1)
|
|
}
|
|
if int32(*(*int8)(unsafe.Pointer(p))) == int32('-') {
|
|
sign = int32(TRUE)
|
|
p += uintptr(1)
|
|
} else {
|
|
if int32(*(*int8)(unsafe.Pointer(p))) == int32('+') {
|
|
p += uintptr(1)
|
|
}
|
|
sign = FALSE
|
|
}
|
|
/*
|
|
* Count the number of digits in the mantissa (including the decimal
|
|
* point), and also locate the decimal point.
|
|
*/
|
|
decPt = -int32(1)
|
|
mantSize = 0
|
|
for {
|
|
c = int32(*(*int8)(unsafe.Pointer(p)))
|
|
if !(BoolInt32(uint32(c)-Uint32FromUint8('0') < Uint32FromInt32(10)) != 0) {
|
|
if c != int32('.') || decPt >= 0 {
|
|
break
|
|
}
|
|
decPt = mantSize
|
|
}
|
|
p += uintptr(1)
|
|
goto _4
|
|
_4:
|
|
;
|
|
mantSize += int32(1)
|
|
}
|
|
/*
|
|
* Now suck up the digits in the mantissa. Use two integers to
|
|
* collect 9 digits each (this is faster than using floating-point).
|
|
* If the mantissa has more than 18 digits, ignore the extras, since
|
|
* they can't affect the value anyway.
|
|
*/
|
|
pExp = p
|
|
p -= uintptr(mantSize)
|
|
if decPt < 0 {
|
|
decPt = mantSize
|
|
} else {
|
|
mantSize -= int32(1) /* One of the digits was the point. */
|
|
}
|
|
if mantSize > int32(18) {
|
|
fracExp = decPt - int32(18)
|
|
mantSize = int32(18)
|
|
} else {
|
|
fracExp = decPt - mantSize
|
|
}
|
|
if mantSize == 0 {
|
|
fraction = float64(0)
|
|
p = string1
|
|
goto done
|
|
} else {
|
|
frac1 = 0
|
|
for {
|
|
if !(mantSize > int32(9)) {
|
|
break
|
|
}
|
|
c = int32(*(*int8)(unsafe.Pointer(p)))
|
|
p += uintptr(1)
|
|
if c == int32('.') {
|
|
c = int32(*(*int8)(unsafe.Pointer(p)))
|
|
p += uintptr(1)
|
|
}
|
|
frac1 = int32(10)*frac1 + (c - int32('0'))
|
|
goto _5
|
|
_5:
|
|
;
|
|
mantSize -= int32(1)
|
|
}
|
|
frac2 = 0
|
|
for {
|
|
if !(mantSize > 0) {
|
|
break
|
|
}
|
|
c = int32(*(*int8)(unsafe.Pointer(p)))
|
|
p += uintptr(1)
|
|
if c == int32('.') {
|
|
c = int32(*(*int8)(unsafe.Pointer(p)))
|
|
p += uintptr(1)
|
|
}
|
|
frac2 = int32(10)*frac2 + (c - int32('0'))
|
|
goto _6
|
|
_6:
|
|
;
|
|
mantSize -= int32(1)
|
|
}
|
|
fraction = float64(1e+09)*float64(float64(frac1)) + float64(float64(frac2))
|
|
}
|
|
/*
|
|
* Skim off the exponent.
|
|
*/
|
|
p = pExp
|
|
if int32(*(*int8)(unsafe.Pointer(p))) == int32('E') || int32(*(*int8)(unsafe.Pointer(p))) == int32('e') {
|
|
p += uintptr(1)
|
|
if int32(*(*int8)(unsafe.Pointer(p))) == int32('-') {
|
|
expSign = int32(TRUE)
|
|
p += uintptr(1)
|
|
} else {
|
|
if int32(*(*int8)(unsafe.Pointer(p))) == int32('+') {
|
|
p += uintptr(1)
|
|
}
|
|
expSign = FALSE
|
|
}
|
|
for BoolInt32(uint32(*(*int8)(unsafe.Pointer(p)))-uint32('0') < uint32(10)) != 0 {
|
|
exp = exp*int32(10) + (int32(*(*int8)(unsafe.Pointer(p))) - int32('0'))
|
|
p += uintptr(1)
|
|
}
|
|
}
|
|
if expSign != 0 {
|
|
exp = fracExp - exp
|
|
} else {
|
|
exp = fracExp + exp
|
|
}
|
|
/*
|
|
* Generate a floating-point number that represents the exponent.
|
|
* Do this by processing the exponent one bit at a time to combine
|
|
* many powers of 2 of 10. Then combine the exponent with the
|
|
* fraction.
|
|
*/
|
|
if exp < 0 {
|
|
expSign = int32(TRUE)
|
|
exp = -exp
|
|
} else {
|
|
expSign = FALSE
|
|
}
|
|
if exp > maxExponent {
|
|
exp = maxExponent
|
|
*(*int32)(unsafe.Pointer(X__errno_location(tls))) = int32(ERANGE)
|
|
}
|
|
dblExp = float64(1)
|
|
d = uintptr(unsafe.Pointer(&powersOf10))
|
|
for {
|
|
if !(exp != 0) {
|
|
break
|
|
}
|
|
if exp&int32(01) != 0 {
|
|
dblExp *= *(*float64)(unsafe.Pointer(d))
|
|
}
|
|
goto _7
|
|
_7:
|
|
;
|
|
exp >>= int32(1)
|
|
d += uintptr(1) * 8
|
|
}
|
|
if expSign != 0 {
|
|
fraction /= dblExp
|
|
} else {
|
|
fraction *= dblExp
|
|
}
|
|
goto done
|
|
done:
|
|
;
|
|
if endPtr != UintptrFromInt32(0) {
|
|
*(*uintptr)(unsafe.Pointer(endPtr)) = p
|
|
}
|
|
if sign != 0 {
|
|
return -fraction
|
|
}
|
|
return fraction
|
|
}
|
|
|
|
var maxExponent = int32(511) /* Largest possible base 10 exponent. Any
|
|
* exponent larger than this will already
|
|
* produce underflow or overflow, so there's
|
|
* no need to worry about additional digits.
|
|
*/
|
|
|
|
var powersOf10 = [9]float64{
|
|
0: float64(10),
|
|
1: float64(100),
|
|
2: float64(10000),
|
|
3: float64(1e+08),
|
|
4: float64(1e+16),
|
|
5: float64(1e+32),
|
|
6: float64(1e+64),
|
|
7: float64(1e+128),
|
|
8: float64(1e+256),
|
|
}
|
|
|
|
// ------------------------------------------------------------------------ (Z)
|