1  
     2  
     3  
     4  
     5  package strconv
     6  
     7  
     8  
     9  
    10  
    11  func lower(c byte) byte {
    12  	return c | ('x' - 'X')
    13  }
    14  
    15  type Error int
    16  
    17  const (
    18  	_ Error = iota
    19  	ErrRange
    20  	ErrSyntax
    21  	ErrBase
    22  	ErrBitSize
    23  )
    24  
    25  func (e Error) Error() string {
    26  	switch e {
    27  	case ErrRange:
    28  		return "value out of range"
    29  	case ErrSyntax:
    30  		return "invalid syntax"
    31  	case ErrBase:
    32  		return "invalid base"
    33  	case ErrBitSize:
    34  		return "invalid bit size"
    35  	}
    36  	return "unknown error"
    37  }
    38  
    39  const intSize = 32 << (^uint(0) >> 63)
    40  
    41  
    42  const IntSize = intSize
    43  
    44  const maxUint64 = 1<<64 - 1
    45  
    46  
    47  
    48  
    49  func ParseUint(s string, base int, bitSize int) (uint64, error) {
    50  	const fnParseUint = "ParseUint"
    51  
    52  	if s == "" {
    53  		return 0, ErrSyntax
    54  	}
    55  
    56  	base0 := base == 0
    57  
    58  	s0 := s
    59  	switch {
    60  	case 2 <= base && base <= 36:
    61  		
    62  
    63  	case base == 0:
    64  		
    65  		base = 10
    66  		if s[0] == '0' {
    67  			switch {
    68  			case len(s) >= 3 && lower(s[1]) == 'b':
    69  				base = 2
    70  				s = s[2:]
    71  			case len(s) >= 3 && lower(s[1]) == 'o':
    72  				base = 8
    73  				s = s[2:]
    74  			case len(s) >= 3 && lower(s[1]) == 'x':
    75  				base = 16
    76  				s = s[2:]
    77  			default:
    78  				base = 8
    79  				s = s[1:]
    80  			}
    81  		}
    82  
    83  	default:
    84  		return 0, ErrBase
    85  	}
    86  
    87  	if bitSize == 0 {
    88  		bitSize = IntSize
    89  	} else if bitSize < 0 || bitSize > 64 {
    90  		return 0, ErrBitSize
    91  	}
    92  
    93  	
    94  	
    95  	var cutoff uint64
    96  	switch base {
    97  	case 10:
    98  		cutoff = maxUint64/10 + 1
    99  	case 16:
   100  		cutoff = maxUint64/16 + 1
   101  	default:
   102  		cutoff = maxUint64/uint64(base) + 1
   103  	}
   104  
   105  	maxVal := uint64(1)<<uint(bitSize) - 1
   106  
   107  	underscores := false
   108  	var n uint64
   109  	for _, c := range []byte(s) {
   110  		var d byte
   111  		switch {
   112  		case c == '_' && base0:
   113  			underscores = true
   114  			continue
   115  		case '0' <= c && c <= '9':
   116  			d = c - '0'
   117  		case 'a' <= lower(c) && lower(c) <= 'z':
   118  			d = lower(c) - 'a' + 10
   119  		default:
   120  			return 0, ErrSyntax
   121  		}
   122  
   123  		if d >= byte(base) {
   124  			return 0, ErrSyntax
   125  		}
   126  
   127  		if n >= cutoff {
   128  			
   129  			return maxVal, ErrRange
   130  		}
   131  		n *= uint64(base)
   132  
   133  		n1 := n + uint64(d)
   134  		if n1 < n || n1 > maxVal {
   135  			
   136  			return maxVal, ErrRange
   137  		}
   138  		n = n1
   139  	}
   140  
   141  	if underscores && !underscoreOK(s0) {
   142  		return 0, ErrSyntax
   143  	}
   144  
   145  	return n, nil
   146  }
   147  
   148  
   149  
   150  
   151  
   152  
   153  
   154  
   155  
   156  
   157  
   158  
   159  
   160  
   161  
   162  
   163  
   164  
   165  
   166  
   167  
   168  
   169  
   170  
   171  
   172  
   173  func ParseInt(s string, base int, bitSize int) (i int64, err error) {
   174  	const fnParseInt = "ParseInt"
   175  
   176  	if s == "" {
   177  		return 0, ErrSyntax
   178  	}
   179  
   180  	
   181  	neg := false
   182  	switch s[0] {
   183  	case '+':
   184  		s = s[1:]
   185  	case '-':
   186  		s = s[1:]
   187  		neg = true
   188  	}
   189  
   190  	
   191  	var un uint64
   192  	un, err = ParseUint(s, base, bitSize)
   193  	if err != nil && err != ErrRange {
   194  		return 0, err
   195  	}
   196  
   197  	if bitSize == 0 {
   198  		bitSize = IntSize
   199  	}
   200  
   201  	cutoff := uint64(1 << uint(bitSize-1))
   202  	if !neg && un >= cutoff {
   203  		return int64(cutoff - 1), ErrRange
   204  	}
   205  	if neg && un > cutoff {
   206  		return -int64(cutoff), ErrRange
   207  	}
   208  	n := int64(un)
   209  	if neg {
   210  		n = -n
   211  	}
   212  	return n, nil
   213  }
   214  
   215  
   216  func Atoi(s string) (int, error) {
   217  	const fnAtoi = "Atoi"
   218  
   219  	sLen := len(s)
   220  	if intSize == 32 && (0 < sLen && sLen < 10) ||
   221  		intSize == 64 && (0 < sLen && sLen < 19) {
   222  		
   223  		s0 := s
   224  		if s[0] == '-' || s[0] == '+' {
   225  			s = s[1:]
   226  			if len(s) < 1 {
   227  				return 0, ErrSyntax
   228  			}
   229  		}
   230  
   231  		n := 0
   232  		for _, ch := range []byte(s) {
   233  			ch -= '0'
   234  			if ch > 9 {
   235  				return 0, ErrSyntax
   236  			}
   237  			n = n*10 + int(ch)
   238  		}
   239  		if s0[0] == '-' {
   240  			n = -n
   241  		}
   242  		return n, nil
   243  	}
   244  
   245  	
   246  	i64, err := ParseInt(s, 10, 0)
   247  	return int(i64), err
   248  }
   249  
   250  
   251  
   252  
   253  func underscoreOK(s string) bool {
   254  	
   255  	
   256  	
   257  	
   258  	
   259  	saw := '^'
   260  	i := 0
   261  
   262  	
   263  	if len(s) >= 1 && (s[0] == '-' || s[0] == '+') {
   264  		s = s[1:]
   265  	}
   266  
   267  	
   268  	hex := false
   269  	if len(s) >= 2 && s[0] == '0' && (lower(s[1]) == 'b' || lower(s[1]) == 'o' || lower(s[1]) == 'x') {
   270  		i = 2
   271  		saw = '0' 
   272  		hex = lower(s[1]) == 'x'
   273  	}
   274  
   275  	
   276  	for ; i < len(s); i++ {
   277  		
   278  		if '0' <= s[i] && s[i] <= '9' || hex && 'a' <= lower(s[i]) && lower(s[i]) <= 'f' {
   279  			saw = '0'
   280  			continue
   281  		}
   282  		
   283  		if s[i] == '_' {
   284  			if saw != '0' {
   285  				return false
   286  			}
   287  			saw = '_'
   288  			continue
   289  		}
   290  		
   291  		if saw == '_' {
   292  			return false
   293  		}
   294  		
   295  		saw = '!'
   296  	}
   297  	return saw != '_'
   298  }
   299  
View as plain text