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: scan functions reading from io.Reader consume the Rune following the last scanned item #1055

Closed
gopherbot opened this issue Aug 28, 2010 · 3 comments

Comments

@gopherbot
Copy link
Contributor

by mt4swm:

What steps will reproduce the problem?
Compile the following go and C programs, and
feed them, for example, with the line ‘123αb’
on stdin. The programs will first try to scan an
integer, then read the rest and print the integer
and the remaining part on stdout again.

    package main
    
    import (
        "fmt"
        "os"
    )
    
    func main() {
        var i int
    
        f := os.Stdin
        if _, e := fmt.Fscanf(f, "%d", &i); e != nil {
            panic(e)
        }
    
        b := make([]byte, 16)
        f.Read(b)
        fmt.Printf("i:%d rest:%s", i, b)
    }

-----

    #include <stdio.h>
    
    int
    main(void)
    {
        char buf[16];
        int i;
    
        fscanf(stdin, "%d", &i);
        buf[0] = '\0';
        fgets(buf, sizeof buf, stdin);
        printf("i:%d rest:%s", i, buf);
    }


What is the expected output?
i:123 rest:αb

What do you see instead?
From the output of the Go version of the program
the α character is missing:
i:123 rest:b

What is your $GOOS?  $GOARCH?
linux/386

Which revision are you using?  (hg identify)
6111/2ace88bde3a0

Please provide any additional information below.
The reason of this slight difference between C-stdio
fscanf and Go fmt/Fscanf is that the latter relies
on io.Reader, which does not allow an Unget, while
stdio/fscanf runs on top of buffered FILE streams.

The simplest fix would be to add a note to the package
documentation, that a Rune might get skipped after
the last verb has been read. In most cases the skipped
Rune likely will be white space, so this won't hurt.

It would be more involving to make fmt.Fscanf behave
similar to C fscanf in this regard. It seems necessary
to have something like an io.UngetReader interface,
which allows not only to Read(), but also to unget one
Rune. Probably bufio could implement that interface.
Those who don't mind losing the delimiting Rune, could
wrap a type around e.g. os.Stdin, implementing an
empty UngetRune method.
@robpike
Copy link
Contributor

robpike commented Aug 29, 2010

Comment 1:

This is a flaw caused by the segmentation of functionality.  A reasonable solution might
involve, along with documentation updates, the suggestion to wrap the input with a
bufio.Reader (or anything else implementing the ability to UngetRune) - except that
bufio doesn't have that ability.  Instead it has Peek, which could be used by the
scanning code if it were written differently.
UngetRune in bufio seems simpler.  At the moment, it can only back up one byte. Taken
under advisement.

Status changed to Accepted.

@robpike
Copy link
Contributor

robpike commented Aug 29, 2010

Comment 2:

Another possibility might be to let scan do all the work (it already does, under the
covers) by exposing the scanState object and having another trio of functions that reuse
it across calls.

@robpike
Copy link
Contributor

robpike commented Sep 14, 2010

Comment 3:

This issue was closed by revision 6ee7997.

Status changed to Fixed.

@golang golang locked and limited conversation to collaborators Jun 24, 2016
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants