gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

etc.go (18524B)


      1 // Copyright 2020 The Libc Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package libc // import "modernc.org/libc"
      6 
      7 import (
      8 	"fmt"
      9 	"io"
     10 	"os"
     11 	"path/filepath"
     12 	"runtime"
     13 	"runtime/debug"
     14 	"sort"
     15 	"strconv"
     16 	"strings"
     17 	"sync"
     18 	"sync/atomic"
     19 	"syscall"
     20 	"time"
     21 	"unsafe"
     22 
     23 	"modernc.org/libc/errno"
     24 	"modernc.org/libc/signal"
     25 	"modernc.org/libc/sys/types"
     26 )
     27 
     28 const (
     29 	allocatorPageOverhead = 4 * unsafe.Sizeof(int(0))
     30 	stackHeaderSize       = unsafe.Sizeof(stackHeader{})
     31 	stackSegmentSize      = 1<<12 - allocatorPageOverhead
     32 	uintptrSize           = unsafe.Sizeof(uintptr(0))
     33 )
     34 
     35 var (
     36 	Covered  = map[uintptr]struct{}{}
     37 	CoveredC = map[string]struct{}{}
     38 	fToken   uintptr
     39 	tid      int32
     40 
     41 	atExit   []func()
     42 	atExitMu sync.Mutex
     43 
     44 	signals   [signal.NSIG]uintptr
     45 	signalsMu sync.Mutex
     46 
     47 	objectMu sync.Mutex
     48 	objects  = map[uintptr]interface{}{}
     49 
     50 	tlsBalance int32
     51 
     52 	_ = origin
     53 	_ = trc
     54 )
     55 
     56 func init() {
     57 	if n := stackHeaderSize; n%16 != 0 {
     58 		panic(fmt.Errorf("internal error: stackHeaderSize %v == %v (mod 16)", n, n%16))
     59 	}
     60 }
     61 
     62 func origin(skip int) string {
     63 	pc, fn, fl, _ := runtime.Caller(skip)
     64 	f := runtime.FuncForPC(pc)
     65 	var fns string
     66 	if f != nil {
     67 		fns = f.Name()
     68 		if x := strings.LastIndex(fns, "."); x > 0 {
     69 			fns = fns[x+1:]
     70 		}
     71 	}
     72 	return fmt.Sprintf("%s:%d:%s", filepath.Base(fn), fl, fns)
     73 }
     74 
     75 func trc(s string, args ...interface{}) string { //TODO-
     76 	switch {
     77 	case s == "":
     78 		s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...)
     79 	default:
     80 		s = fmt.Sprintf(s, args...)
     81 	}
     82 	r := fmt.Sprintf("%s: TRC %s", origin(2), s)
     83 	fmt.Fprintf(os.Stdout, "%s\n", r)
     84 	os.Stdout.Sync()
     85 	return r
     86 }
     87 
     88 func todo(s string, args ...interface{}) string { //TODO-
     89 	switch {
     90 	case s == "":
     91 		s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...)
     92 	default:
     93 		s = fmt.Sprintf(s, args...)
     94 	}
     95 	r := fmt.Sprintf("%s: TODOTODO %s", origin(2), s) //TODOOK
     96 	if dmesgs {
     97 		dmesg("%s", r)
     98 	}
     99 	fmt.Fprintf(os.Stdout, "%s\n", r)
    100 	fmt.Fprintf(os.Stdout, "%s\n", debug.Stack()) //TODO-
    101 	os.Stdout.Sync()
    102 	os.Exit(1)
    103 	panic("unrechable")
    104 }
    105 
    106 var coverPCs [1]uintptr //TODO not concurrent safe
    107 
    108 func Cover() {
    109 	runtime.Callers(2, coverPCs[:])
    110 	Covered[coverPCs[0]] = struct{}{}
    111 }
    112 
    113 func CoverReport(w io.Writer) error {
    114 	var a []string
    115 	pcs := make([]uintptr, 1)
    116 	for pc := range Covered {
    117 		pcs[0] = pc
    118 		frame, _ := runtime.CallersFrames(pcs).Next()
    119 		a = append(a, fmt.Sprintf("%s:%07d:%s", filepath.Base(frame.File), frame.Line, frame.Func.Name()))
    120 	}
    121 	sort.Strings(a)
    122 	_, err := fmt.Fprintf(w, "%s\n", strings.Join(a, "\n"))
    123 	return err
    124 }
    125 
    126 func CoverC(s string) {
    127 	CoveredC[s] = struct{}{}
    128 }
    129 
    130 func CoverCReport(w io.Writer) error {
    131 	var a []string
    132 	for k := range CoveredC {
    133 		a = append(a, k)
    134 	}
    135 	sort.Strings(a)
    136 	_, err := fmt.Fprintf(w, "%s\n", strings.Join(a, "\n"))
    137 	return err
    138 }
    139 
    140 func token() uintptr { return atomic.AddUintptr(&fToken, 1) }
    141 
    142 func addObject(o interface{}) uintptr {
    143 	t := token()
    144 	objectMu.Lock()
    145 	objects[t] = o
    146 	objectMu.Unlock()
    147 	return t
    148 }
    149 
    150 func getObject(t uintptr) interface{} {
    151 	objectMu.Lock()
    152 	o := objects[t]
    153 	if o == nil {
    154 		panic(todo("", t))
    155 	}
    156 
    157 	objectMu.Unlock()
    158 	return o
    159 }
    160 
    161 func removeObject(t uintptr) {
    162 	objectMu.Lock()
    163 	if _, ok := objects[t]; !ok {
    164 		panic(todo(""))
    165 	}
    166 
    167 	delete(objects, t)
    168 	objectMu.Unlock()
    169 }
    170 
    171 func (t *TLS) setErrno(err interface{}) {
    172 	if memgrind {
    173 		if atomic.SwapInt32(&t.reentryGuard, 1) != 0 {
    174 			panic(todo("concurrent use of TLS instance %p", t))
    175 		}
    176 
    177 		defer func() {
    178 			if atomic.SwapInt32(&t.reentryGuard, 0) != 1 {
    179 				panic(todo("concurrent use of TLS instance %p", t))
    180 			}
    181 		}()
    182 	}
    183 	// if dmesgs {
    184 	// 	dmesg("%v: %T(%v)\n%s", origin(1), err, err, debug.Stack())
    185 	// }
    186 again:
    187 	switch x := err.(type) {
    188 	case int:
    189 		*(*int32)(unsafe.Pointer(t.errnop)) = int32(x)
    190 	case int32:
    191 		*(*int32)(unsafe.Pointer(t.errnop)) = x
    192 	case *os.PathError:
    193 		err = x.Err
    194 		goto again
    195 	case syscall.Errno:
    196 		*(*int32)(unsafe.Pointer(t.errnop)) = int32(x)
    197 	case *os.SyscallError:
    198 		err = x.Err
    199 		goto again
    200 	default:
    201 		panic(todo("%T", x))
    202 	}
    203 }
    204 
    205 // Close frees the resources of t.
    206 func (t *TLS) Close() {
    207 	t.Free(int(unsafe.Sizeof(int32(0))))
    208 	if memgrind {
    209 		if t.stackHeaderBalance != 0 {
    210 			panic(todo("non zero stack header balance: %d", t.stackHeaderBalance))
    211 		}
    212 
    213 		atomic.AddInt32(&tlsBalance, -1)
    214 	}
    215 	t.pthreadData.close(t)
    216 	*t = TLS{}
    217 }
    218 
    219 // Alloc allocates n bytes of thread-local storage. It must be paired with a
    220 // call to t.Free(n), using the same n. The order matters. This is ok:
    221 //
    222 //	t.Alloc(11)
    223 //		t.Alloc(22)
    224 //		t.Free(22)
    225 //	t.Free(11)
    226 //
    227 // This is not correct:
    228 //
    229 //	t.Alloc(11)
    230 //		t.Alloc(22)
    231 //		t.Free(11)
    232 //	t.Free(22)
    233 func (t *TLS) Alloc(n int) (r uintptr) {
    234 	if memgrind {
    235 		if atomic.SwapInt32(&t.reentryGuard, 1) != 0 {
    236 			panic(todo("concurrent use of TLS instance %p", t))
    237 		}
    238 
    239 		defer func() {
    240 			if atomic.SwapInt32(&t.reentryGuard, 0) != 1 {
    241 				panic(todo("concurrent use of TLS instance %p", t))
    242 			}
    243 		}()
    244 	}
    245 	n += 15
    246 	n &^= 15
    247 	if t.stack.free >= n {
    248 		r = t.stack.sp
    249 		t.stack.free -= n
    250 		t.stack.sp += uintptr(n)
    251 		return r
    252 	}
    253 	//if we have a next stack
    254 	if nstack := t.stack.next; nstack != 0 {
    255 		if (*stackHeader)(unsafe.Pointer(nstack)).free >= n {
    256 			*(*stackHeader)(unsafe.Pointer(t.stack.page)) = t.stack
    257 			t.stack = *(*stackHeader)(unsafe.Pointer(nstack))
    258 			r = t.stack.sp
    259 			t.stack.free -= n
    260 			t.stack.sp += uintptr(n)
    261 			return r
    262 		}
    263 		nstack := *(*stackHeader)(unsafe.Pointer(t.stack.next))
    264 		for ; ; nstack = *(*stackHeader)(unsafe.Pointer(nstack.next)) {
    265 			if memgrind {
    266 				if atomic.AddInt32(&t.stackHeaderBalance, -1) < 0 {
    267 					panic(todo("negative stack header balance"))
    268 				}
    269 			}
    270 			Xfree(t, nstack.page)
    271 			if nstack.next == 0 {
    272 				break
    273 			}
    274 		}
    275 		t.stack.next = 0
    276 	}
    277 
    278 	if t.stack.page != 0 {
    279 		*(*stackHeader)(unsafe.Pointer(t.stack.page)) = t.stack
    280 	}
    281 
    282 	rq := n + int(stackHeaderSize)
    283 	if rq%int(stackSegmentSize) != 0 {
    284 		rq -= rq % int(stackSegmentSize)
    285 		rq += int(stackSegmentSize)
    286 	}
    287 	t.stack.free = rq - int(stackHeaderSize)
    288 	t.stack.prev = t.stack.page
    289 
    290 	rq += 15
    291 	rq &^= 15
    292 	t.stack.page = Xmalloc(t, types.Size_t(rq))
    293 	if t.stack.page == 0 {
    294 		panic("OOM")
    295 	}
    296 
    297 	if memgrind {
    298 		atomic.AddInt32(&t.stackHeaderBalance, 1)
    299 	}
    300 	t.stack.sp = t.stack.page + stackHeaderSize
    301 
    302 	r = t.stack.sp
    303 	t.stack.free -= n
    304 	t.stack.sp += uintptr(n)
    305 	if t.stack.prev != 0 {
    306 		(*stackHeader)(unsafe.Pointer(t.stack.prev)).next = t.stack.page
    307 	}
    308 
    309 	return r
    310 }
    311 
    312 // this declares how many stack frames are kept alive before being freed
    313 const stackFrameKeepalive = 2
    314 
    315 // Free deallocates n bytes of thread-local storage. See TLS.Alloc for details
    316 // on correct usage.
    317 func (t *TLS) Free(n int) {
    318 	if memgrind {
    319 		if atomic.SwapInt32(&t.reentryGuard, 1) != 0 {
    320 			panic(todo("concurrent use of TLS instance %p", t))
    321 		}
    322 
    323 		defer func() {
    324 			if atomic.SwapInt32(&t.reentryGuard, 0) != 1 {
    325 				panic(todo("concurrent use of TLS instance %p", t))
    326 			}
    327 		}()
    328 	}
    329 	n += 15
    330 	n &^= 15
    331 	t.stack.free += n
    332 	t.stack.sp -= uintptr(n)
    333 	if t.stack.sp != t.stack.page+stackHeaderSize {
    334 		return
    335 	}
    336 
    337 	nstack := t.stack
    338 
    339 	//if we are the first one, just free all of them
    340 	if t.stack.prev == 0 {
    341 		for ; ; nstack = *(*stackHeader)(unsafe.Pointer(nstack.next)) {
    342 			if memgrind {
    343 				if atomic.AddInt32(&t.stackHeaderBalance, -1) < 0 {
    344 					panic(todo("negative stack header balance"))
    345 				}
    346 			}
    347 			Xfree(t, nstack.page)
    348 			if nstack.next == 0 {
    349 				break
    350 			}
    351 		}
    352 		t.stack = stackHeader{}
    353 		return
    354 	}
    355 
    356 	//look if we are in the last n stackframes (n=stackFrameKeepalive)
    357 	//if we find something just return and set the current stack pointer to the previous one
    358 	for i := 0; i < stackFrameKeepalive; i++ {
    359 		if nstack.next == 0 {
    360 			*((*stackHeader)(unsafe.Pointer(t.stack.page))) = t.stack
    361 			t.stack = *(*stackHeader)(unsafe.Pointer(t.stack.prev))
    362 			return
    363 		}
    364 		nstack = *(*stackHeader)(unsafe.Pointer(nstack.next))
    365 	}
    366 
    367 	//else only free the last
    368 	if memgrind {
    369 		if atomic.AddInt32(&t.stackHeaderBalance, -1) < 0 {
    370 			panic(todo("negative stack header balance"))
    371 		}
    372 	}
    373 	Xfree(t, nstack.page)
    374 	(*stackHeader)(unsafe.Pointer(nstack.prev)).next = 0
    375 	*(*stackHeader)(unsafe.Pointer(t.stack.page)) = t.stack
    376 	t.stack = *(*stackHeader)(unsafe.Pointer(t.stack.prev))
    377 }
    378 
    379 type stackHeader struct {
    380 	free int     // bytes left in page
    381 	page uintptr // stack page
    382 	prev uintptr // prev stack page = prev stack header
    383 	next uintptr // next stack page = next stack header
    384 	sp   uintptr // next allocation address
    385 	_    stackHeaderPadding
    386 }
    387 
    388 func cString(t *TLS, s string) uintptr { //TODO-
    389 	n := len(s)
    390 	p := Xmalloc(t, types.Size_t(n)+1)
    391 	if p == 0 {
    392 		panic("OOM")
    393 	}
    394 
    395 	copy((*RawMem)(unsafe.Pointer(p))[:n:n], s)
    396 	*(*byte)(unsafe.Pointer(p + uintptr(n))) = 0
    397 	return p
    398 }
    399 
    400 // VaList fills a varargs list at p with args and returns p.  The list must
    401 // have been allocated by caller and it must not be in Go managed memory, ie.
    402 // it must be pinned. Caller is responsible for freeing the list.
    403 //
    404 // Individual arguments must be one of int, uint, int32, uint32, int64, uint64,
    405 // float64, uintptr or Intptr. Other types will panic.
    406 //
    407 // This function supports code generated by ccgo/v3. For manually constructed
    408 // var args it's recommended to use the NewVaList function instead.
    409 //
    410 // Note: The C translated to Go varargs ABI alignment for all types is 8 on all
    411 // architectures.
    412 func VaList(p uintptr, args ...interface{}) (r uintptr) {
    413 	if p&7 != 0 {
    414 		panic("internal error")
    415 	}
    416 
    417 	r = p
    418 	for _, v := range args {
    419 		switch x := v.(type) {
    420 		case int:
    421 			*(*int64)(unsafe.Pointer(p)) = int64(x)
    422 		case int32:
    423 			*(*int64)(unsafe.Pointer(p)) = int64(x)
    424 		case int64:
    425 			*(*int64)(unsafe.Pointer(p)) = x
    426 		case uint:
    427 			*(*uint64)(unsafe.Pointer(p)) = uint64(x)
    428 		case uint16:
    429 			*(*uint64)(unsafe.Pointer(p)) = uint64(x)
    430 		case uint32:
    431 			*(*uint64)(unsafe.Pointer(p)) = uint64(x)
    432 		case uint64:
    433 			*(*uint64)(unsafe.Pointer(p)) = x
    434 		case float64:
    435 			*(*float64)(unsafe.Pointer(p)) = x
    436 		case uintptr:
    437 			*(*uintptr)(unsafe.Pointer(p)) = x
    438 		default:
    439 			panic(todo("invalid VaList argument type: %T", x))
    440 		}
    441 		p += 8
    442 	}
    443 	return r
    444 }
    445 
    446 // NewVaListN returns a newly allocated va_list for n items. The caller of
    447 // NewVaListN is responsible for freeing the va_list.
    448 func NewVaListN(n int) (va_list uintptr) {
    449 	return Xmalloc(nil, types.Size_t(8*n))
    450 }
    451 
    452 // NewVaList is like VaList but automatically allocates the correct amount of
    453 // memory for all of the items in args.
    454 //
    455 // The va_list return value is used to pass the constructed var args to var
    456 // args accepting functions. The caller of NewVaList is responsible for freeing
    457 // the va_list.
    458 func NewVaList(args ...interface{}) (va_list uintptr) {
    459 	return VaList(NewVaListN(len(args)), args...)
    460 }
    461 
    462 func VaInt32(app *uintptr) int32 {
    463 	ap := *(*uintptr)(unsafe.Pointer(app))
    464 	if ap == 0 {
    465 		return 0
    466 	}
    467 
    468 	ap = roundup(ap, 8)
    469 	v := int32(*(*int64)(unsafe.Pointer(ap)))
    470 	ap += 8
    471 	*(*uintptr)(unsafe.Pointer(app)) = ap
    472 	return v
    473 }
    474 
    475 func VaUint32(app *uintptr) uint32 {
    476 	ap := *(*uintptr)(unsafe.Pointer(app))
    477 	if ap == 0 {
    478 		return 0
    479 	}
    480 
    481 	ap = roundup(ap, 8)
    482 	v := uint32(*(*uint64)(unsafe.Pointer(ap)))
    483 	ap += 8
    484 	*(*uintptr)(unsafe.Pointer(app)) = ap
    485 	return v
    486 }
    487 
    488 func VaInt64(app *uintptr) int64 {
    489 	ap := *(*uintptr)(unsafe.Pointer(app))
    490 	if ap == 0 {
    491 		return 0
    492 	}
    493 
    494 	ap = roundup(ap, 8)
    495 	v := *(*int64)(unsafe.Pointer(ap))
    496 	ap += 8
    497 	*(*uintptr)(unsafe.Pointer(app)) = ap
    498 	return v
    499 }
    500 
    501 func VaUint64(app *uintptr) uint64 {
    502 	ap := *(*uintptr)(unsafe.Pointer(app))
    503 	if ap == 0 {
    504 		return 0
    505 	}
    506 
    507 	ap = roundup(ap, 8)
    508 	v := *(*uint64)(unsafe.Pointer(ap))
    509 	ap += 8
    510 	*(*uintptr)(unsafe.Pointer(app)) = ap
    511 	return v
    512 }
    513 
    514 func VaFloat32(app *uintptr) float32 {
    515 	ap := *(*uintptr)(unsafe.Pointer(app))
    516 	if ap == 0 {
    517 		return 0
    518 	}
    519 
    520 	ap = roundup(ap, 8)
    521 	v := *(*float64)(unsafe.Pointer(ap))
    522 	ap += 8
    523 	*(*uintptr)(unsafe.Pointer(app)) = ap
    524 	return float32(v)
    525 }
    526 
    527 func VaFloat64(app *uintptr) float64 {
    528 	ap := *(*uintptr)(unsafe.Pointer(app))
    529 	if ap == 0 {
    530 		return 0
    531 	}
    532 
    533 	ap = roundup(ap, 8)
    534 	v := *(*float64)(unsafe.Pointer(ap))
    535 	ap += 8
    536 	*(*uintptr)(unsafe.Pointer(app)) = ap
    537 	return v
    538 }
    539 
    540 func VaUintptr(app *uintptr) uintptr {
    541 	ap := *(*uintptr)(unsafe.Pointer(app))
    542 	if ap == 0 {
    543 		return 0
    544 	}
    545 
    546 	ap = roundup(ap, 8)
    547 	v := *(*uintptr)(unsafe.Pointer(ap))
    548 	ap += 8
    549 	*(*uintptr)(unsafe.Pointer(app)) = ap
    550 	return v
    551 }
    552 
    553 func roundup(n, to uintptr) uintptr {
    554 	if r := n % to; r != 0 {
    555 		return n + to - r
    556 	}
    557 
    558 	return n
    559 }
    560 
    561 func GoString(s uintptr) string {
    562 	if s == 0 {
    563 		return ""
    564 	}
    565 
    566 	var buf []byte
    567 	for {
    568 		b := *(*byte)(unsafe.Pointer(s))
    569 		if b == 0 {
    570 			return string(buf)
    571 		}
    572 
    573 		buf = append(buf, b)
    574 		s++
    575 	}
    576 }
    577 
    578 // GoBytes returns a byte slice from a C char* having length len bytes.
    579 func GoBytes(s uintptr, len int) []byte {
    580 	if len == 0 {
    581 		return nil
    582 	}
    583 
    584 	return (*RawMem)(unsafe.Pointer(s))[:len:len]
    585 }
    586 
    587 func Bool32(b bool) int32 {
    588 	if b {
    589 		return 1
    590 	}
    591 
    592 	return 0
    593 }
    594 
    595 func Bool64(b bool) int64 {
    596 	if b {
    597 		return 1
    598 	}
    599 
    600 	return 0
    601 }
    602 
    603 type sorter struct {
    604 	len  int
    605 	base uintptr
    606 	sz   uintptr
    607 	f    func(*TLS, uintptr, uintptr) int32
    608 	t    *TLS
    609 }
    610 
    611 func (s *sorter) Len() int { return s.len }
    612 
    613 func (s *sorter) Less(i, j int) bool {
    614 	return s.f(s.t, s.base+uintptr(i)*s.sz, s.base+uintptr(j)*s.sz) < 0
    615 }
    616 
    617 func (s *sorter) Swap(i, j int) {
    618 	p := uintptr(s.base + uintptr(i)*s.sz)
    619 	q := uintptr(s.base + uintptr(j)*s.sz)
    620 	for i := 0; i < int(s.sz); i++ {
    621 		*(*byte)(unsafe.Pointer(p)), *(*byte)(unsafe.Pointer(q)) = *(*byte)(unsafe.Pointer(q)), *(*byte)(unsafe.Pointer(p))
    622 		p++
    623 		q++
    624 	}
    625 }
    626 
    627 func CString(s string) (uintptr, error) {
    628 	n := len(s)
    629 	p := Xmalloc(nil, types.Size_t(n)+1)
    630 	if p == 0 {
    631 		return 0, fmt.Errorf("CString: cannot allocate %d bytes", n+1)
    632 	}
    633 
    634 	copy((*RawMem)(unsafe.Pointer(p))[:n:n], s)
    635 	*(*byte)(unsafe.Pointer(p + uintptr(n))) = 0
    636 	return p, nil
    637 }
    638 
    639 func GetEnviron() (r []string) {
    640 	for p := Environ(); ; p += unsafe.Sizeof(p) {
    641 		q := *(*uintptr)(unsafe.Pointer(p))
    642 		if q == 0 {
    643 			return r
    644 		}
    645 
    646 		r = append(r, GoString(q))
    647 	}
    648 }
    649 
    650 func strToUint64(t *TLS, s uintptr, base int32) (seenDigits, neg bool, next uintptr, n uint64, err int32) {
    651 	var c byte
    652 out:
    653 	for {
    654 		c = *(*byte)(unsafe.Pointer(s))
    655 		switch c {
    656 		case ' ', '\t', '\n', '\r', '\v', '\f':
    657 			s++
    658 		case '+':
    659 			s++
    660 			break out
    661 		case '-':
    662 			s++
    663 			neg = true
    664 			break out
    665 		default:
    666 			break out
    667 		}
    668 	}
    669 	for {
    670 		c = *(*byte)(unsafe.Pointer(s))
    671 		var digit uint64
    672 		switch base {
    673 		case 10:
    674 			switch {
    675 			case c >= '0' && c <= '9':
    676 				seenDigits = true
    677 				digit = uint64(c) - '0'
    678 			default:
    679 				return seenDigits, neg, s, n, 0
    680 			}
    681 		case 16:
    682 			if c >= 'A' && c <= 'F' {
    683 				c = c + ('a' - 'A')
    684 			}
    685 			switch {
    686 			case c >= '0' && c <= '9':
    687 				seenDigits = true
    688 				digit = uint64(c) - '0'
    689 			case c >= 'a' && c <= 'f':
    690 				seenDigits = true
    691 				digit = uint64(c) - 'a' + 10
    692 			default:
    693 				return seenDigits, neg, s, n, 0
    694 			}
    695 		default:
    696 			panic(todo("", base))
    697 		}
    698 		n0 := n
    699 		n = uint64(base)*n + digit
    700 		if n < n0 { // overflow
    701 			return seenDigits, neg, s, n0, errno.ERANGE
    702 		}
    703 
    704 		s++
    705 	}
    706 }
    707 
    708 func strToFloatt64(t *TLS, s uintptr, bits int) (n float64, errno int32) {
    709 	var b []byte
    710 	var neg bool
    711 
    712 	defer func() {
    713 		var err error
    714 		if n, err = strconv.ParseFloat(string(b), bits); err != nil {
    715 			panic(todo(""))
    716 		}
    717 
    718 		if neg {
    719 			n = -n
    720 		}
    721 	}()
    722 
    723 	var c byte
    724 out:
    725 	for {
    726 		c = *(*byte)(unsafe.Pointer(s))
    727 		switch c {
    728 		case ' ', '\t', '\n', '\r', '\v', '\f':
    729 			s++
    730 		case '+':
    731 			s++
    732 			break out
    733 		case '-':
    734 			s++
    735 			neg = true
    736 			break out
    737 		default:
    738 			break out
    739 		}
    740 	}
    741 	for {
    742 		c = *(*byte)(unsafe.Pointer(s))
    743 		switch {
    744 		case c >= '0' && c <= '9':
    745 			b = append(b, c)
    746 		case c == '.':
    747 			b = append(b, c)
    748 			s++
    749 			for {
    750 				c = *(*byte)(unsafe.Pointer(s))
    751 				switch {
    752 				case c >= '0' && c <= '9':
    753 					b = append(b, c)
    754 				case c == 'e' || c == 'E':
    755 					b = append(b, c)
    756 					s++
    757 					for {
    758 						c = *(*byte)(unsafe.Pointer(s))
    759 						switch {
    760 						case c == '+' || c == '-':
    761 							b = append(b, c)
    762 							s++
    763 							for {
    764 								c = *(*byte)(unsafe.Pointer(s))
    765 								switch {
    766 								case c >= '0' && c <= '9':
    767 									b = append(b, c)
    768 								default:
    769 									return
    770 								}
    771 
    772 								s++
    773 							}
    774 						default:
    775 							panic(todo("%q %q", b, string(c)))
    776 						}
    777 					}
    778 				default:
    779 					return
    780 				}
    781 
    782 				s++
    783 			}
    784 		default:
    785 			panic(todo("%q %q", b, string(c)))
    786 		}
    787 
    788 		s++
    789 	}
    790 }
    791 
    792 func parseZone(s string) (name string, off int) {
    793 	_, name, off, _ = parseZoneOffset(s, false)
    794 	return name, off
    795 }
    796 
    797 func parseZoneOffset(s string, offOpt bool) (string, string, int, bool) {
    798 	s0 := s
    799 	name := s
    800 	for len(s) != 0 {
    801 		switch c := s[0]; {
    802 		case c >= 'A' && c <= 'Z', c >= 'a' && c <= 'z', c == '_', c == '/':
    803 			s = s[1:]
    804 		default:
    805 			name = name[:len(name)-len(s)]
    806 			if len(name) < 3 {
    807 				panic(todo("%q", s0))
    808 			}
    809 
    810 			if offOpt {
    811 				if len(s) == 0 {
    812 					return "", name, 0, false
    813 				}
    814 
    815 				if c := s[0]; (c < '0' || c > '9') && c != '+' && c != '-' {
    816 					return s, name, 0, false
    817 				}
    818 			}
    819 
    820 			s, off := parseOffset(s)
    821 			return s, name, off, true
    822 		}
    823 	}
    824 	return "", s0, 0, true
    825 }
    826 
    827 // [+|-]hh[:mm[:ss]]
    828 func parseOffset(s string) (string, int) {
    829 	if len(s) == 0 {
    830 		panic(todo(""))
    831 	}
    832 
    833 	k := 1
    834 	switch s[0] {
    835 	case '+':
    836 		// nop
    837 		s = s[1:]
    838 	case '-':
    839 		k = -1
    840 		s = s[1:]
    841 	}
    842 	s, hh, ok := parseUint(s)
    843 	if !ok {
    844 		panic(todo(""))
    845 	}
    846 
    847 	n := hh * 3600
    848 	if len(s) == 0 || s[0] != ':' {
    849 		return s, k * n
    850 	}
    851 
    852 	s = s[1:] // ':'
    853 	if len(s) == 0 {
    854 		panic(todo(""))
    855 	}
    856 
    857 	s, mm, ok := parseUint(s)
    858 	if !ok {
    859 		panic(todo(""))
    860 	}
    861 
    862 	n += mm * 60
    863 	if len(s) == 0 || s[0] != ':' {
    864 		return s, k * n
    865 	}
    866 
    867 	s = s[1:] // ':'
    868 	if len(s) == 0 {
    869 		panic(todo(""))
    870 	}
    871 
    872 	s, ss, _ := parseUint(s)
    873 	return s, k * (n + ss)
    874 }
    875 
    876 func parseUint(s string) (string, int, bool) {
    877 	var ok bool
    878 	var r int
    879 	for len(s) != 0 {
    880 		switch c := s[0]; {
    881 		case c >= '0' && c <= '9':
    882 			ok = true
    883 			r0 := r
    884 			r = 10*r + int(c) - '0'
    885 			if r < r0 {
    886 				panic(todo(""))
    887 			}
    888 
    889 			s = s[1:]
    890 		default:
    891 			return s, r, ok
    892 		}
    893 	}
    894 	return s, r, ok
    895 }
    896 
    897 // https://stackoverflow.com/a/53052382
    898 //
    899 // isTimeDST returns true if time t occurs within daylight saving time
    900 // for its time zone.
    901 func isTimeDST(t time.Time) bool {
    902 	// If the most recent (within the last year) clock change
    903 	// was forward then assume the change was from std to dst.
    904 	hh, mm, _ := t.UTC().Clock()
    905 	tClock := hh*60 + mm
    906 	for m := -1; m > -12; m-- {
    907 		// assume dst lasts for at least one month
    908 		hh, mm, _ := t.AddDate(0, m, 0).UTC().Clock()
    909 		clock := hh*60 + mm
    910 		if clock != tClock {
    911 			return clock > tClock
    912 		}
    913 	}
    914 	// assume no dst
    915 	return false
    916 }