-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
os: CtrlZ doesn't work on Windows #17427
Comments
Sorry for breaking it. Need a test for it, so we don't break it again, I will have a look into it when I have time. Or feel free to sen the change (with test), if you like. Thank you. Alex |
CL https://golang.org/cl/31114 mentions this issue. |
I looked at CL 31114 and I am not sure new behavior (the way you convert Ctrl+Z into bytes/errors returned by os.Stdin,Read) in CL is correct. @rsc approved original CtrlZ change (CL 4310), so he, probably, knows what we want here. I run your program above with this small change:
Then I pressed:
I see this output:
Russ, what whould new code for os.Stdin.Read return here? Assume we have changed the program above to loop forever instead of exiting after io.Copy returns. Should os.Stdin.Read return more data after it returns io.EOF? Should os.Stdin.Read return 26 when we press CtrlZ? Thank you. Alex |
I propose that the first ^Z return 0, io.EOF and also set a bit so that all future reads return 0, io.EOF without reading any more data from the console. That way if you are at a Go program and type abc^Zdef then the program exits (one assumes because it saw EOF) with def still remaining in the console buffer for reading by the next program that checks. |
Totally okay to me. And I propose that return 0, io.EOF for each typing ^Z.
This should be possible to read twice. |
@mattn is right, and I was wrong: each ^Z should result in 0, io.EOF coming back, but then more reading should continue to read from the console. This matches what happens today on Unix with ^D on consoles
|
I am fine with whatever you decide here. @mattn, please, make appropriate changes to CL 31114 and will close this. Thank you. Alex |
I'll take a look. Currently, I found two problems.
The first is caused that readConsole return immediately if it finish the convertion of mbytes.
I'm guessing that we may need to call readFile with large bytes ex 4096 (BUFSIZ). Or another idea, readConsole handle |
Current implementation seems not work for multi-byte string. Passing [1]byte into ReadFile break the trailing byte of double byte character set. For example, Typing
Please give me your opinion. |
2649868#diff-558a93088b8a6149f759cc86274f67d7R255 Implementation using ReadConsole allocate []int16 which have same number of characters. So I prefer the first way. |
@alexbrainman I'll update CL 31114 and revert implementation last change. And I'll add bits trick to read 4 bytes which is minimum size of multi-byte. It will be bigger than len(b). But the readbuf will be read at next call of readConsole. The minimum size of multi-byte should be 4 because Windows can change current code page with func (f *File) readConsole(b []byte) (n int, err error) {
if len(b) == 0 {
return 0, nil
}
if len(f.readbuf) == 0 {
numBytes := len(b)
// Windows can't read bytes over max of int16.
// Some versions of Windows can read even less.
// See golang.org/issue/13697.
if numBytes > 10000 {
numBytes = 10000
} else if numBytes < 4 {
// Read minimum size of multi-byte
numBytes = 4
}
mbytes := make([]byte, numBytes)
var nmb uint32
err := syscall.ReadFile(f.fd, mbytes, &nmb, nil)
if err != nil {
return 0, err
}
if nmb > 0 {
var pmb *byte
if len(b) > 0 {
pmb = &mbytes[0]
}
ccp := windows.GetConsoleCP()
// Convert from 8-bit console encoding to UTF16.
// MultiByteToWideChar defaults to Unicode NFC form, which is the expected one.
nwc, err := windows.MultiByteToWideChar(ccp, 0, pmb, int32(nmb), nil, 0)
if err != nil {
return 0, err
}
wchars := make([]uint16, nwc)
pwc := &wchars[0]
nwc, err = windows.MultiByteToWideChar(ccp, 0, pmb, int32(nmb), pwc, nwc)
if err != nil {
return 0, err
}
f.readbuf = utf16.Decode(wchars[:nwc])
}
}
for i, r := range f.readbuf {
if utf8.RuneLen(r) > len(b) {
f.readbuf = f.readbuf[i:]
return n, nil
}
nr := utf8.EncodeRune(b, r)
b = b[nr:]
n += nr
}
f.readbuf = nil
return n, nil
} |
I found a bug of ReadFile on console. See following code. #include <windows.h>
#include <stdio.h>
int
main(int argc, char* argv[]) {
HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
char buf[7];
DWORD nread;
BOOL result;
result = ReadFile(h, buf, sizeof(buf)-1, &nread, NULL);
printf("result=%d, nread=%d\n", result, nread);
buf[nread] = 0;
puts(buf);
result = ReadFile(h, buf, sizeof(buf)-1, &nread, NULL);
printf("result=%d, nread=%d\n", result, nread);
buf[nread] = 0;
puts(buf);
return 0;
} When typing |
CL https://golang.org/cl/33451 mentions this issue. |
What version of Go are you using (
go version
)?go version devel +1af769d Thu Oct 13 06:16:53 2016 +0000 windows/amd64
What operating system and processor architecture are you using (
go env
)?Windows7 64bit
What did you do?
What did you expect to see?
break blocking of io.Copy.
What did you see instead?
doesn't break blocking of io.Copy.
I suggest to change like below
I wonder what way is best for go because below's C code work with different behavior to go.
Microsoft C runtime seeks break fread when typing CTRL-Z in the beigin of the line. But my patch break even though typing CTRL-Z at end of the line.
I don't say that Go have to work as same as C. But I worry about the right way for go.
related issue #17097, #16857
The text was updated successfully, but these errors were encountered: