Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fmt: Scanf supports %X for integers but not strings. [Patch+Tests included] #12940

Closed
benthor opened this issue Oct 14, 2015 · 4 comments
Closed

fmt: Scanf supports %X for integers but not strings. [Patch+Tests included] #12940

benthor opened this issue Oct 14, 2015 · 4 comments

Comments

@benthor
Copy link

@benthor benthor commented Oct 14, 2015

The fmt Documentation states two things:

  • Firstly, for Printing:
String and slice of bytes (treated equivalently with these verbs):

%s  the uninterpreted bytes of the string or slice
%q  a double-quoted string safely escaped with Go syntax
%x  base 16, lower-case, two characters per byte
%X  base 16, upper-case, two characters per byte
  • Secondly, for Scanning:
The formats behave analogously to those of Printf with the following exceptions:

%p is not implemented
%T is not implemented
%e %E %f %F %g %G are all equivalent and scan any floating point or complex value
%s and %v on strings scan a space-delimited token
Flags # and + are not implemented.

(Note how %X is not listed among the exceptions)

So given the following:

var (
    hex = "48C3A43F"
    b   []byte
    i   int
    s   string
)

fmt.Sscanf(hex, "%X", &b)
fmt.Sscanf(hex, "%X", &i)
fmt.Sscanf(hex, "%X", &s)
fmt.Println("Bytes:  ", b)
fmt.Println("Integer:", i)
fmt.Println("String: ", s)

one would assume that b, i and s now respectively contain byte and integer representations of the hex-value 48C3A43F. However, this is not the case! Instead, the following output is generated:

Bytes:   []
Integer: 1220781119
String:  

Only the integer variable gets correctly assigned.

But: Substituting "%X" with lower-case "%x" in the example above gives the desired output:

Bytes:   [72 195 164 63]
Integer: 1220781119
String:  Hä?

I conclude that this behavior is a bug. Either the verb "%X" should be explicitly listed as an exception in the Scanning-documentation or it should be fully supported for all relevant types.

I therefore submit the following patch (including additional relevant tests) which adds support for upper-case "%X" when scanning into []byte or strings:

diff --git a/src/fmt/scan.go b/src/fmt/scan.go
index e3e0fd0..68cb8bb 100644
--- a/src/fmt/scan.go
+++ b/src/fmt/scan.go
@@ -813,7 +813,7 @@ func (s *ss) scanComplex(verb rune, n int) complex128 {
 // convertString returns the string represented by the next input characters.
 // The format of the input is determined by the verb.
 func (s *ss) convertString(verb rune) (str string) {
-   if !s.okVerb(verb, "svqx", "string") {
+   if !s.okVerb(verb, "svqxX", "string") {
        return ""
    }
    s.skipSpace(false)
@@ -821,7 +821,7 @@ func (s *ss) convertString(verb rune) (str string) {
    switch verb {
    case 'q':
        str = s.quotedString()
-   case 'x':
+   case 'x', 'X': // s.hexString() supports both upper and lower-case hex strings, so we can support both verbs here.
        str = s.hexString()
    default:
        str = string(s.token(true, notSpace)) // %s and %v just return the next word
diff --git a/src/fmt/scan_test.go b/src/fmt/scan_test.go
index 334c4a6..1924c02 100644
--- a/src/fmt/scan_test.go
+++ b/src/fmt/scan_test.go
@@ -255,12 +255,14 @@ var scanfTests = []ScanfTest{
    // Strings
    {"%s", "using-%s\n", &stringVal, "using-%s"},
    {"%x", "7573696e672d2578\n", &stringVal, "using-%x"},
+   {"%X", "7573696E672D2558\n", &stringVal, "using-%X"},
    {"%q", `"quoted\twith\\do\u0075bl\x65s"` + "\n", &stringVal, "quoted\twith\\doubles"},
    {"%q", "`quoted with backs`\n", &stringVal, "quoted with backs"},

    // Byte slices
    {"%s", "bytes-%s\n", &bytesVal, []byte("bytes-%s")},
    {"%x", "62797465732d2578\n", &bytesVal, []byte("bytes-%x")},
+   {"%X", "62797465732D2558\n", &bytesVal, []byte("bytes-%X")},
    {"%q", `"bytes\rwith\vdo\u0075bl\x65s"` + "\n", &bytesVal, []byte("bytes\rwith\vdoubles")},
    {"%q", "`bytes with backs`\n", &bytesVal, []byte("bytes with backs")},
@nodirt
Copy link
Contributor

@nodirt nodirt commented Oct 14, 2015

Normally patches are sent on Gerrit. https://golang.org/doc/contribute.html

@benthor
Copy link
Author

@benthor benthor commented Oct 14, 2015

Thanks will do

@gopherbot
Copy link

@gopherbot gopherbot commented Oct 14, 2015

CL https://golang.org/cl/15689 mentions this issue.

@adg adg closed this in 26fe24c Oct 20, 2015
@golang golang locked and limited conversation to collaborators Oct 24, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants
You can’t perform that action at this time.