fmt: Added SkipSpace() function to fmt's ScanState interface.

Users of the Scan() infrastructure that employ ReadRune() rather than
Token() need a way to skip leading spaces and newlines as set by the
the parent, Fscan(), Fscanln, or Fscanf(). As the internal methods and
boolean flags are not exported, this new function was added here and
in the Int and Nat Scan() functions of the big package. (fmt.Rat did
not need change since it uses Token()) Also added Printf style format
code support to int types and tests for same to int_test.go

R=r, r, gri, mtj
CC=golang-dev
https://golang.org/cl/4634074
This commit is contained in:
Michael T. Jones 2011-06-24 17:26:45 -07:00 committed by Robert Griesemer
parent 5d4eea6a2f
commit d94e350f48
3 changed files with 96 additions and 5 deletions

View File

@ -368,11 +368,60 @@ func (x *Int) Format(s fmt.State, ch int) {
format = "0X%s"
}
}
if x.neg {
format = "-" + format
t := fmt.Sprintf(format, x.abs.string(cs))
// insert spaces in hexadecimal formats if needed
if len(t) > 0 && s.Flag(' ') && (ch == 'x' || ch == 'X') {
spaces := (len(t)+1)/2 - 1
spaced := make([]byte, len(t)+spaces)
var i, j int
spaced[i] = t[j]
i++
j++
if len(t)&1 == 0 {
spaced[i] = t[j]
i++
j++
}
for j < len(t) {
spaced[i] = ' '
i++
spaced[i] = t[j]
i++
j++
spaced[i] = t[j]
i++
j++
}
t = string(spaced)
}
fmt.Fprintf(s, format, x.abs.string(cs))
// determine sign prefix
prefix := ""
switch {
case x.neg:
prefix = "-"
case s.Flag('+'):
prefix = "+"
case s.Flag(' ') && ch != 'x' && ch != 'X':
prefix = " "
}
// fill to minimum width and prepend sign prefix
if width, ok := s.Width(); ok && len(t)+len(prefix) < width {
if s.Flag('0') {
t = fmt.Sprintf("%s%0*d%s", prefix, width-len(t)-len(prefix), 0, t)
} else {
if s.Flag('-') {
width = -width
}
t = fmt.Sprintf("%*s", width, prefix+t)
}
} else if prefix != "" {
t = prefix + t
}
fmt.Fprint(s, t)
}
@ -417,6 +466,7 @@ func (z *Int) scan(r io.RuneScanner, base int) (*Int, int, os.Error) {
// 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':
@ -585,7 +635,7 @@ func ProbablyPrime(z *Int, n int) bool {
}
// Rand sets z to a pseudo-random number in [0, n) and returns z.
// Rand sets z to a pseudo-random number in [0, n) and returns z.
func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
z.neg = false
if n.neg == true || len(n.abs) == 0 {

View File

@ -376,6 +376,35 @@ var formatTests = []struct {
{"-10", "%#X", "-0XA"},
{"10", "%#y", "%!y(big.Int=10)"},
{"-10", "%#y", "%!y(big.Int=-10)"},
{"1234", "%d", "1234"},
{"1234", "%3d", "1234"},
{"1234", "%4d", "1234"},
{"-1234", "%d", "-1234"},
{"1234", "% 5d", " 1234"},
{"1234", "%+5d", "+1234"},
{"1234", "%-5d", "1234 "},
{"1234", "%x", "4d2"},
{"1234", "%X", "4D2"},
{"1234", "% x", "4 d2"},
{"-1234", "%3x", "-4d2"},
{"-1234", "%4x", "-4d2"},
{"-1234", "%5x", " -4d2"},
{"-1234", "%-5x", "-4d2 "},
{"-1234", "% x", "-4 d2"},
{"1234", "%03d", "1234"},
{"1234", "%04d", "1234"},
{"1234", "%05d", "01234"},
{"1234", "%06d", "001234"},
{"-1234", "%06d", "-01234"},
{"1234", "%+06d", "+01234"},
{"1234", "% 06d", " 01234"},
{"1234", "%-6d", "1234 "},
{"1234", "%-06d", "001234"},
{"-1234", "%-06d", "-01234"},
{"10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", // 10**100
"% x",
"12 49 ad 25 94 c3 7c eb 0b 27 84 c4 ce 0b f3 8a ce 40 8e 21 1a 7c aa b2 43 08 a8 2e 8f 10 00 00 00 00 00 00 00 00 00 00 00 00"},
}
@ -391,7 +420,7 @@ func TestFormat(t *testing.T) {
}
output := fmt.Sprintf(test.format, x)
if output != test.output {
t.Errorf("#%d got %s; want %s", i, output, test.output)
t.Errorf("#%d got %q; want %q", i, output, test.output)
}
}
}

View File

@ -35,6 +35,10 @@ type ScanState interface {
ReadRune() (rune int, size int, err os.Error)
// UnreadRune causes the next call to ReadRune to return the same rune.
UnreadRune() os.Error
// SkipSpace skips space in the input. Newlines are treated as space
// unless the scan operation is Scanln, Fscanln or Sscanln, in which case
// a newline is treated as EOF.
SkipSpace()
// Token skips space in the input if skipSpace is true, then returns the
// run of Unicode code points c satisfying f(c). If f is nil,
// !unicode.IsSpace(c) is used; that is, the token will hold non-space
@ -267,6 +271,14 @@ func notSpace(r int) bool {
return !unicode.IsSpace(r)
}
// skipSpace provides Scan() methods the ability to skip space and newline characters
// in keeping with the current scanning mode set by format strings and Scan()/Scanln().
func (s *ss) SkipSpace() {
s.skipSpace(false)
}
// readRune is a structure to enable reading UTF-8 encoded code points
// from an io.Reader. It is used if the Reader given to the scanner does
// not already implement io.RuneReader.