1package types
2
3import (
4	"fmt"
5	"strings"
6)
7
8// An IntMode is a mode for parsing integer values, representing a set of
9// accepted bases.
10type IntMode uint8
11
12// IntMode values for ParseInt; can be combined using binary or.
13const (
14	Dec IntMode = 1 << iota
15	Hex
16	Oct
17)
18
19// String returns a string representation of IntMode; e.g. `IntMode(Dec|Hex)`.
20func (m IntMode) String() string {
21	var modes []string
22	if m&Dec != 0 {
23		modes = append(modes, "Dec")
24	}
25	if m&Hex != 0 {
26		modes = append(modes, "Hex")
27	}
28	if m&Oct != 0 {
29		modes = append(modes, "Oct")
30	}
31	return "IntMode(" + strings.Join(modes, "|") + ")"
32}
33
34var errIntAmbig = fmt.Errorf("ambiguous integer value; must include '0' prefix")
35
36func prefix0(val string) bool {
37	return strings.HasPrefix(val, "0") || strings.HasPrefix(val, "-0")
38}
39
40func prefix0x(val string) bool {
41	return strings.HasPrefix(val, "0x") || strings.HasPrefix(val, "-0x")
42}
43
44// ParseInt parses val using mode into intptr, which must be a pointer to an
45// integer kind type. Non-decimal value require prefix `0` or `0x` in the cases
46// when mode permits ambiguity of base; otherwise the prefix can be omitted.
47func ParseInt(intptr interface{}, val string, mode IntMode) error {
48	val = strings.TrimSpace(val)
49	verb := byte(0)
50	switch mode {
51	case Dec:
52		verb = 'd'
53	case Dec + Hex:
54		if prefix0x(val) {
55			verb = 'v'
56		} else {
57			verb = 'd'
58		}
59	case Dec + Oct:
60		if prefix0(val) && !prefix0x(val) {
61			verb = 'v'
62		} else {
63			verb = 'd'
64		}
65	case Dec + Hex + Oct:
66		verb = 'v'
67	case Hex:
68		if prefix0x(val) {
69			verb = 'v'
70		} else {
71			verb = 'x'
72		}
73	case Oct:
74		verb = 'o'
75	case Hex + Oct:
76		if prefix0(val) {
77			verb = 'v'
78		} else {
79			return errIntAmbig
80		}
81	}
82	if verb == 0 {
83		panic("unsupported mode")
84	}
85	return ScanFully(intptr, val, verb)
86}
87