github.com/afumu/libc@v0.0.6/etc.go (about)

     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 "github.com/afumu/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  	"github.com/afumu/libc/errno"
    24  	"github.com/afumu/libc/signal"
    25  	"github.com/afumu/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  }