Пример #1
0
// ScanEnum is a helper function to simplify the implementation of fmt.Scanner
// methods for "enum-like" types, that is, user-defined types where the set of
// values and string representations is fixed.
// ScanEnum allows multiple string representations for the same value.
//
// State is the state passed to the implementation of the fmt.Scanner method.
// Values holds as map values the values of the type, with their string
// representations as keys.
// If fold is true, comparison of the string representation uses
// strings.EqualFold, otherwise the equal operator for strings.
//
// On a match, ScanEnum stops after reading the last rune of the matched string,
// and returns the corresponding value together with a nil error.
// On no match, ScanEnum attempts to unread the last rune (the first rune that
// could not potentially match any of the values), and returns a non-nil error,
// together with a nil value for interface{}.
// On I/O error, ScanEnum returns the I/O error, together with a nil value for
// interface{}.
//
func scanEnum(state fmt.ScanState, values map[string]interface{}, fold bool) (
	interface{}, error) {
	//
	rd := make([]rune, 0, scanEnumBufferHint)
	keys := make(map[string]struct{}, len(values)) // potential keys
	for s, _ := range values {
		keys[s] = struct{}{}
	}
	for {
		r, _, err := state.ReadRune()
		if err != nil {
			return nil, err
		}
		rd = append(rd, r)
		srd := string(rd)
		lrd := len(srd)
		for s, _ := range keys {
			if strEq(srd, s, fold) {
				return values[s], nil
			}
			if len(rd) < len(s) && !strEq(srd, s[:lrd], fold) {
				delete(keys, s)
			}
		}
		if len(keys) == 0 {
			state.UnreadRune()
			return nil, fmt.Errorf("unsupported value %q", srd)
		}
	}
	panic("never reached")
}
Пример #2
0
func (u *unit) Scan(state fmt.ScanState, verb rune) error {
	var x float64
	_, err := fmt.Fscan(state, &x)
	if err != nil {
		return err
	}
	tok, err := state.Token(false, unicode.IsLetter)
	if err != nil {
		return err
	}
	units := string(tok)
	switch units {
	case "ns", "", "b":
		// already in nanoseconds or bytes
	case "us":
		x *= 1e3
	case "ms":
		x *= 1e6
	case "s":
		x *= 1e9
	case "k", "kb", "K", "KB":
		x *= 1024
	case "m", "mb", "M", "MB":
		x *= 1024 * 1024
	default:
		return fmt.Errorf("unknown time or size unit %q", units)
	}
	*u = unit(x)
	return nil
}
Пример #3
0
func (w *word) Scan(state fmt.ScanState, verb rune) error {
	tok, err := state.Token(false, func(r rune) bool { return unicode.IsLetter(r) || r == '.' })
	if err == nil && len(tok) == 0 {
		return errEmpty
	}
	*w = word(tok)
	return err
}
Пример #4
0
// Scan is a support routine for fmt.Scanner; it sets z to the value of
// the scanned number. It accepts the decimal formats 'd' and 'f', and
// handles both equivalently. Bases 2, 8, 16 are not supported.
// The scale of z is the number of digits after the decimal point
// (including any trailing 0s), or 0 if there is no decimal point.
func (z *Dec) Scan(s fmt.ScanState, ch rune) error {
	if ch != 'd' && ch != 'f' && ch != 's' && ch != 'v' {
		return fmt.Errorf("Dec.Scan: invalid verb '%c'", ch)
	}
	s.SkipSpace()
	_, err := z.scan(s)
	return err
}
Пример #5
0
func scanInt(state fmt.ScanState) (int, error) {
	token, err := state.Token(true, func(r rune) bool {
		return unicode.IsDigit(r)
	})
	if err != nil {
		return 0, err
	}
	res, err := strconv.ParseInt(string(token), 0, 64)
	return int(res), err
}
Пример #6
0
func (c *coords) Scan(state fmt.ScanState, verb rune) error {
	rx, _, _ := state.ReadRune()
	ry, _, _ := state.ReadRune()
	if rx < 'A' || 'G' < rx || ry < '1' || '8' < ry {
		return fmt.Errorf("Illegal chess coordinates: <%c, %c>", rx, ry)
	}
	c.x = int(rx - 'A')
	c.y = int(ry - '1')
	return nil
}
Пример #7
0
// Scan implements fmt.Scanner interface. This makes it possible to use
// fmt.Sscan*() functions to parse syslog facility codes. Also
// "gcfg" package can parse them in configuration files.
func (s *Severity) Scan(state fmt.ScanState, verb rune) error {
	sevstr, err := state.Token(false, func(r rune) bool { return true })
	if err != nil {
		return err
	}
	sev, ok := severityCodes[string(sevstr)]
	if !ok {
		return errors.New(`invalid severity "` + string(sevstr) + `"`)
	}
	*s = sev
	return nil
}
Пример #8
0
// Implement fmt.Scanner interface. This makes it possible to use fmt.Sscan*()
// functions to parse syslog facility codes directly. Also "gcfg" package can
// parse them in configuration files.
func (f *SyslogFacility) Scan(state fmt.ScanState, verb rune) error {
	facstr, err := state.Token(false, func(r rune) bool { return true })
	if err != nil {
		return err
	}
	fac, ok := syslogFacilityCodes[string(facstr)]
	if !ok {
		return errors.New(`invalid facility "` + string(facstr) + `"`)
	}
	*f = fac
	return nil
}
Пример #9
0
// Implement fmt.Scanner interface.
func (i *ibpiID) Scan(state fmt.ScanState, verb rune) error {
	ibpistr, err := state.Token(false, func(r rune) bool { return true })
	if err != nil {
		return err
	}
	ibpiid, ok := ibpiNameToId[string(ibpistr)]
	if !ok {
		return errors.New(`invalid IBPI string "` + string(ibpistr) + `"`)
	}
	*i = ibpiid
	return nil
}
Пример #10
0
// Scan is a support routine for fmt.Scanner. It accepts the formats
// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
	tok, err := s.Token(true, ratTok)
	if err != nil {
		return err
	}
	if strings.IndexRune("efgEFGv", ch) < 0 {
		return errors.New("Rat.Scan: invalid verb")
	}
	if _, ok := z.SetString(string(tok)); !ok {
		return errors.New("Rat.Scan: invalid syntax")
	}
	return nil
}
Пример #11
0
func (h *Hand) Scan(st fmt.ScanState, x int) os.Error {
	str, e := st.Token()
	if e != nil {
		return e
	}
	l := len(str)
	hSpades := ReadSuit(str)
	str, e = st.Token()
	if e != nil {
		return e
	}
	hHearts := ReadSuit(str[l:])
	l = len(str)
	str, e = st.Token()
	if e != nil {
		return e
	}
	hDiamonds := ReadSuit(str[l:])
	l = len(str)
	str, e = st.Token()
	if e != nil {
		return e
	}
	hClubs := ReadSuit(str[l:])
	*h = Hand(hClubs) + (Hand(hDiamonds) << 8) + (Hand(hHearts) << 16) + (Hand(hSpades) << 24)
	return e
}
Пример #12
0
// Scan is a support routine for fmt.Scanner; it sets z to the value of
// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
func (z *Int) Scan(s fmt.ScanState, ch int) os.Error {
	s.SkipSpace() // skip leading space characters
	base := 0
	switch ch {
	case 'b':
		base = 2
	case 'o':
		base = 8
	case 'd':
		base = 10
	case 'x', 'X':
		base = 16
	case 's', 'v':
		// let scan determine the base
	default:
		return os.NewError("Int.Scan: invalid verb")
	}
	_, _, err := z.scan(s, base)
	return err
}
Пример #13
0
func (pKey *peerKey) Scan(state fmt.ScanState, verb rune) error {
	ipB, err := state.Token(true, nil)
	if err != nil {
		return err
	}

	pKey.peerIP = net.ParseIP(string(ipB))

	macB, err := state.Token(true, nil)
	if err != nil {
		return err
	}

	pKey.peerMac, err = net.ParseMAC(string(macB))
	if err != nil {
		return err
	}

	return nil
}
Пример #14
0
// Implement fmt.Scanner interface.
func (smapp *stringToStringMap) Scan(state fmt.ScanState, verb rune) error {
	smap := make(stringToStringMap)
	for {
		tok, err := state.Token(true, nil)
		if err != nil {
			return err
		}
		if len(tok) == 0 { // end of string
			break
		}
		str := string(tok)
		pair := strings.SplitN(str, ":", 2)
		if len(pair) != 2 {
			return errors.New(`invalid map entry "` + str + `"`)
		}
		smap[pair[0]] = pair[1]
	}
	*smapp = smap
	return nil
}
Пример #15
0
func (h Histogram) Scan(state fmt.ScanState, verb rune) (e error) {
	braceCount := 0
	matchBrace := func(r rune) bool {
		if r == '{' {
			braceCount += 1
		} else if r == '{' {
			braceCount -= 1
		}

		return braceCount > 0
	}

	var data []byte
	if data, e = state.Token(true, matchBrace); e != nil {
		return
	}

	json.Unmarshal(data, &h)

	return
}
Пример #16
0
func (d *Direction) Scan(state fmt.ScanState, verb rune) error {
	bs, err := state.Token(true, nil)
	if err != nil {
		return err
	}

	bs = bytes.ToLower(bs)
	switch {
	case bytes.Compare(bs, []byte("up")) == 0:
		*d = UP
	case bytes.Compare(bs, []byte("down")) == 0:
		*d = DOWN
	case bytes.Compare(bs, []byte("left")) == 0:
		*d = LEFT
	case bytes.Compare(bs, []byte("right")) == 0:
		*d = RIGHT
	default:
		return fmt.Errorf("Invalid direction: %s", bs)
	}
	return nil
}
Пример #17
0
// Scan implements the Scanner interface.
func (d *Dimension) Scan(state fmt.ScanState, verb rune) error {
	var v Dimension

	if verb != 'v' {
		return fmt.Errorf("Dimension.Scan: invalid verb %c", verb)
	}

	// Scan number.
	tok, err := state.Token(true, numberToken)
	if err != nil {
		return err
	}
	value := string(tok)
	if value == "" {
		return fmt.Errorf("number is required")
	}
	if err := v.Value.Set(value); err != nil {
		return fmt.Errorf("%q is not a valid dimension: %v", value, err)
	}

	// Scan unit.  The unit follows immediately after the number.
	tok, err = state.Token(false, unitToken)
	if err != nil {
		return err
	}
	unit := string(tok)
	if err := v.Unit.Set(unit); err != nil {
		return fmt.Errorf("\"%s%s\" is not a valid dimension: %v", value, unit, err)
	}
	if v.Unit == NoUnit && v.Value != 0 {
		return fmt.Errorf("%q is not a valid dimension: unit is required", value)
	}

	*d = v

	return nil
}
Пример #18
0
func (s *Suit) Scan(st fmt.ScanState, x int) os.Error {
	str, e := st.Token()
	*s = ReadSuit(str)
	return e
}
Пример #19
0
func (sum *SpamSum) Scan(state fmt.ScanState, verb rune) error {
	var blocksize int
	var leftPart, rightPart, blockPart, buffer []byte
	var err error

	if blockPart, err = state.Token(false, // do not skip spaces
		func(r rune) bool {
			return unicode.IsDigit(r)
		}); err != nil {
		return err
	} else if len(blockPart) == 0 {
		return errors.New("Cannot read block size.")
	}

	if blocksize, err = strconv.Atoi(string(blockPart)); err != nil {
		return err
	} else if blocksize < 3 {
		return errors.New("Block size too small")
	}

	if r, _, err := state.ReadRune(); err != nil {
		return err
	} else if r != ':' {
		return errors.New("Invalid token delimiter")
	}

	if buffer, err = state.Token(false, // do not skip spaces
		func(r rune) bool {
			return (bytes.IndexRune([]byte(b64), r) != -1)
		}); err != nil {
		return err
	} else if len(buffer) > SpamsumLength {
		return errors.New("First base64 string too long")
	}

	leftPart = make([]byte, len(buffer))
	copy(leftPart, buffer[:])

	if r, _, err := state.ReadRune(); err != nil {
		return err
	} else if r != ':' {
		return errors.New("Invalid token delimiter")
	}

	if buffer, err = state.Token(false, // do not skip spaces
		func(r rune) bool {
			return (bytes.IndexRune([]byte(b64), r) != -1)
		}); err != nil {
		return err
	} else if len(buffer) > (SpamsumLength / 2) {
		return errors.New("Second base64 string too long")
	}

	rightPart = make([]byte, len(buffer))
	copy(rightPart[:], buffer)

	sum.blocksize = uint32(blocksize)
	copy(sum.leftPart[:], leftPart)
	copy(sum.rightPart[:], rightPart)
	sum.leftIndex = len(leftPart)
	sum.rightIndex = len(rightPart)

	return nil
}
Пример #20
0
func (node *Node) Scan(state fmt.ScanState, verb int) os.Error {
	nameBytes, err := state.Token(true, nil)
	if err != nil {
		return err
	}
	if len(nameBytes) == 0 {
		return os.EOF
	}
	nameBytes = dup(nameBytes)

	extIPBytes, err := state.Token(true, nil)
	if err != nil {
		return err
	}
	extIPBytes = dup(extIPBytes)

	intIP4Bytes, err := state.Token(true, nil)
	if err != nil {
		return err
	}
	intIP4Bytes = dup(intIP4Bytes)

	intIP6Bytes, err := state.Token(true, nil)
	if err != nil {
		return err
	}
	intIP6Bytes = dup(intIP6Bytes)

	name := string(nameBytes)
	if len(name) < 1 {
		return NameTooShort
	}
	if len(name) > maxNameLen {
		return NameTooLong
	}

	extIP := net.ParseIP(string(extIPBytes))
	if extIP == nil {
		return ExtIPInvalid
	}

	intIP4 := net.ParseIP(string(intIP4Bytes))
	if intIP4 == nil {
		return IntIP4Invalid
	}
	intIP4 = intIP4.To4()
	if intIP4 == nil {
		return IntIP6Invalid
	}

	intIP6 := net.ParseIP(string(intIP6Bytes))
	if intIP6 == nil {
		return IntIP6Invalid
	}
	if intIP6.To4() != nil {
		return IntIP6Invalid
	}

	node.Name = name
	node.ExtIP = extIP
	node.IntIP4 = intIP4
	node.IntIP6 = intIP6

	return nil
}
Пример #21
0
// Scan is a support routine for fmt.Scanner; it sets z to the value of
// the scanned number. It accepts formats whose verbs are supported by
// fmt.Scan for floating point values, which are:
// 'b' (binary), 'e', 'E', 'f', 'F', 'g' and 'G'.
// Scan doesn't handle ±Inf.
func (z *Float) Scan(s fmt.ScanState, ch rune) error {
	s.SkipSpace()
	_, _, err := z.scan(byteReader{s}, 0)
	return err
}
Пример #22
0
Файл: int.go Проект: locusf/gmp
// Scan is a support routine for fmt.Scanner; it sets z to the value of
// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
func (z *Int) Scan(s fmt.ScanState, ch rune) error {
	s.SkipSpace() // skip leading space characters
	base := 0
	switch ch {
	case 'b':
		base = 2
	case 'o':
		base = 8
	case 'd':
		base = 10
	case 'x', 'X':
		base = 16
	case 's', 'v':
		// let scan determine the base
	case 'z':
		base = 60
	default:
		return errors.New("Int.Scan: invalid verb")
	}
	charset := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz."
	if base != 0 {
		charset = charset[:base]
	}

	// Read the number into in
	in := make([]byte, 0, 16)
	var err error
	var n int
	for {
		ch, n, err = s.ReadRune()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}
		if n > 1 {
			// Wide character - must be the end
			s.UnreadRune()
			break
		}
		if len(in) == 0 {
			if ch == '+' {
				// Skip leading + as gmp doesn't understand them
				continue
			}
			if ch == '-' {
				goto ok
			}
		}
		if len(in) == 1 && base == 0 {
			if ch == 'b' || ch == 'x' {
				goto ok
			}
		}
		if !strings.ContainsRune(charset, ch) {
			// Bad character - end
			s.UnreadRune()
			break
		}
	ok:
		in = append(in, byte(ch))
	}

	// Use GMP to convert it as it is very efficient for large numbers
	z.doinit()
	// null terminate for C
	in = append(in, 0)
	if C.mpz_set_str(&z.i[0], (*C.char)(unsafe.Pointer(&in[0])), C.int(base)) < 0 {
		return errors.New("Int.Scan: failed")
	}
	return nil
}