Use syscall consts, check for errors,

Also rename func for non-windows specific names.

Signed-off-by: Sachin Joshi <sachin_jayant_joshi@hotmail.com>
This commit is contained in:
Sachin Joshi 2015-03-06 17:04:35 -08:00
parent c23a02e41a
commit 27c2a55648
5 changed files with 40 additions and 30 deletions

View file

@ -30,7 +30,7 @@ func StdStreams() (stdOut io.Writer, stdErr io.Writer, stdIn io.ReadCloser) {
return os.Stdout, os.Stderr, os.Stdin return os.Stdout, os.Stderr, os.Stdin
} }
func GetHandleInfo(in interface{}) (uintptr, bool) { func GetFdInfo(in interface{}) (uintptr, bool) {
var inFd uintptr var inFd uintptr
var isTerminalIn bool var isTerminalIn bool
if file, ok := in.(*os.File); ok { if file, ok := in.(*os.File); ok {

View file

@ -107,8 +107,8 @@ func MakeRaw(fd uintptr) (*State, error) {
return state, nil return state, nil
} }
// GetHandleInfo returns file descriptor and bool indicating whether the file is a terminal // GetFdInfo returns file descriptor and bool indicating whether the file is a terminal
func GetHandleInfo(in interface{}) (uintptr, bool) { func GetFdInfo(in interface{}) (uintptr, bool) {
return winconsole.GetHandleInfo(in) return winconsole.GetHandleInfo(in)
} }

View file

@ -83,11 +83,6 @@ const (
ANSI_MAX_CMD_LENGTH = 256 ANSI_MAX_CMD_LENGTH = 256
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms683231(v=vs.85).aspx
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
STD_ERROR_HANDLE = -12
MAX_INPUT_BUFFER = 1024 MAX_INPUT_BUFFER = 1024
DEFAULT_WIDTH = 80 DEFAULT_WIDTH = 80
DEFAULT_HEIGHT = 24 DEFAULT_HEIGHT = 24
@ -212,7 +207,10 @@ func StdStreams() (stdOut io.Writer, stdErr io.Writer, stdIn io.ReadCloser) {
} }
// Save current screen buffer info // Save current screen buffer info
handle, _ := syscall.GetStdHandle(STD_OUTPUT_HANDLE) handle, err := syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE)
if nil != err {
panic("This should never happen as it is predefined handle.")
}
screenBufferInfo, err := GetConsoleScreenBufferInfo(uintptr(handle)) screenBufferInfo, err := GetConsoleScreenBufferInfo(uintptr(handle))
if err == nil { if err == nil {
handler.screenBufferInfo = screenBufferInfo handler.screenBufferInfo = screenBufferInfo
@ -225,26 +223,36 @@ func StdStreams() (stdOut io.Writer, stdErr io.Writer, stdIn io.ReadCloser) {
wrappedWriter: os.Stdout, wrappedWriter: os.Stdout,
emulator: handler, emulator: handler,
command: make([]byte, 0, ANSI_MAX_CMD_LENGTH), command: make([]byte, 0, ANSI_MAX_CMD_LENGTH),
fd: uintptr(handle),
} }
} else { } else {
stdOut = os.Stdout stdOut = os.Stdout
} }
if IsTerminal(os.Stderr.Fd()) { if IsTerminal(os.Stderr.Fd()) {
handle, err := syscall.GetStdHandle(syscall.STD_ERROR_HANDLE)
if nil != err {
panic("This should never happen as it is predefined handle.")
}
stdErr = &terminalWriter{ stdErr = &terminalWriter{
wrappedWriter: os.Stderr, wrappedWriter: os.Stderr,
emulator: handler, emulator: handler,
command: make([]byte, 0, ANSI_MAX_CMD_LENGTH), command: make([]byte, 0, ANSI_MAX_CMD_LENGTH),
fd: uintptr(handle),
} }
} else { } else {
stdErr = os.Stderr stdErr = os.Stderr
} }
if IsTerminal(os.Stdin.Fd()) { if IsTerminal(os.Stdin.Fd()) {
handle, err := syscall.GetStdHandle(syscall.STD_INPUT_HANDLE)
if nil != err {
panic("This should never happen as it is predefined handle.")
}
stdIn = &terminalReader{ stdIn = &terminalReader{
wrappedReader: os.Stdin, wrappedReader: os.Stdin,
emulator: handler, emulator: handler,
command: make([]byte, 0, ANSI_MAX_CMD_LENGTH), command: make([]byte, 0, ANSI_MAX_CMD_LENGTH),
fd: uintptr(handle),
} }
} else { } else {
stdIn = os.Stdin stdIn = os.Stdin
@ -626,7 +634,7 @@ func getWindowsTextAttributeForAnsiValue(originalFlag WORD, defaultValue WORD, a
} }
// HandleOutputCommand interpretes the Ansi commands and then makes appropriate Win32 calls // HandleOutputCommand interpretes the Ansi commands and then makes appropriate Win32 calls
func (term *WindowsTerminal) HandleOutputCommand(command []byte) (n int, err error) { func (term *WindowsTerminal) HandleOutputCommand(fd uintptr, command []byte) (n int, err error) {
// console settings changes need to happen in atomic way // console settings changes need to happen in atomic way
term.outMutex.Lock() term.outMutex.Lock()
defer term.outMutex.Unlock() defer term.outMutex.Unlock()
@ -636,7 +644,7 @@ func (term *WindowsTerminal) HandleOutputCommand(command []byte) (n int, err err
parsedCommand := parseAnsiCommand(command) parsedCommand := parseAnsiCommand(command)
// use appropriate handle // use appropriate handle
handle, _ := syscall.GetStdHandle(STD_OUTPUT_HANDLE) handle := syscall.Handle(fd)
switch parsedCommand.Command { switch parsedCommand.Command {
case "m": case "m":
@ -891,7 +899,7 @@ func (term *WindowsTerminal) HandleOutputCommand(command []byte) (n int, err err
} }
// WriteChars writes the bytes to given writer. // WriteChars writes the bytes to given writer.
func (term *WindowsTerminal) WriteChars(w io.Writer, p []byte) (n int, err error) { func (term *WindowsTerminal) WriteChars(fd uintptr, w io.Writer, p []byte) (n int, err error) {
return w.Write(p) return w.Write(p)
} }
@ -1027,8 +1035,8 @@ func mapKeystokeToTerminalString(keyEvent *KEY_EVENT_RECORD, escapeSequence []by
// getAvailableInputEvents polls the console for availble events // getAvailableInputEvents polls the console for availble events
// The function does not return until at least one input record has been read. // The function does not return until at least one input record has been read.
func getAvailableInputEvents() (inputEvents []INPUT_RECORD, err error) { func getAvailableInputEvents(fd uintptr) (inputEvents []INPUT_RECORD, err error) {
handle, _ := syscall.GetStdHandle(STD_INPUT_HANDLE) handle := syscall.Handle(fd)
if nil != err { if nil != err {
return nil, err return nil, err
} }
@ -1064,7 +1072,7 @@ func getTranslatedKeyCodes(inputEvents []INPUT_RECORD, escapeSequence []byte) st
} }
// ReadChars reads the characters from the given reader // ReadChars reads the characters from the given reader
func (term *WindowsTerminal) ReadChars(w io.Reader, p []byte) (n int, err error) { func (term *WindowsTerminal) ReadChars(fd uintptr, w io.Reader, p []byte) (n int, err error) {
n = 0 n = 0
for n < len(p) { for n < len(p) {
select { select {
@ -1076,7 +1084,7 @@ func (term *WindowsTerminal) ReadChars(w io.Reader, p []byte) (n int, err error)
if n > 0 { if n > 0 {
return n, nil return n, nil
} }
inputEvents, _ := getAvailableInputEvents() inputEvents, _ := getAvailableInputEvents(fd)
if inputEvents != nil { if inputEvents != nil {
if len(inputEvents) == 0 && nil != err { if len(inputEvents) == 0 && nil != err {
return n, err return n, err
@ -1094,7 +1102,7 @@ func (term *WindowsTerminal) ReadChars(w io.Reader, p []byte) (n int, err error)
} }
// HandleInputSequence interprets the input sequence command // HandleInputSequence interprets the input sequence command
func (term *WindowsTerminal) HandleInputSequence(command []byte) (n int, err error) { func (term *WindowsTerminal) HandleInputSequence(fd uintptr, command []byte) (n int, err error) {
return 0, nil return 0, nil
} }

View file

@ -27,10 +27,10 @@ const (
// Interface that implements terminal handling // Interface that implements terminal handling
type terminalEmulator interface { type terminalEmulator interface {
HandleOutputCommand(command []byte) (n int, err error) HandleOutputCommand(fd uintptr, command []byte) (n int, err error)
HandleInputSequence(command []byte) (n int, err error) HandleInputSequence(fd uintptr, command []byte) (n int, err error)
WriteChars(w io.Writer, p []byte) (n int, err error) WriteChars(fd uintptr, w io.Writer, p []byte) (n int, err error)
ReadChars(w io.Reader, p []byte) (n int, err error) ReadChars(fd uintptr, w io.Reader, p []byte) (n int, err error)
} }
type terminalWriter struct { type terminalWriter struct {
@ -38,6 +38,7 @@ type terminalWriter struct {
emulator terminalEmulator emulator terminalEmulator
command []byte command []byte
inSequence bool inSequence bool
fd uintptr
} }
type terminalReader struct { type terminalReader struct {
@ -45,6 +46,7 @@ type terminalReader struct {
emulator terminalEmulator emulator terminalEmulator
command []byte command []byte
inSequence bool inSequence bool
fd uintptr
} }
// http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html // http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html
@ -91,7 +93,7 @@ func (tw *terminalWriter) Write(p []byte) (n int, err error) {
if !isXtermOscSequence(tw.command, p[current]) { if !isXtermOscSequence(tw.command, p[current]) {
// found the last command character. // found the last command character.
// Now we have a complete command. // Now we have a complete command.
nchar, err := tw.emulator.HandleOutputCommand(tw.command) nchar, err := tw.emulator.HandleOutputCommand(tw.fd, tw.command)
totalWritten += nchar totalWritten += nchar
if err != nil { if err != nil {
return totalWritten, err return totalWritten, err
@ -110,7 +112,7 @@ func (tw *terminalWriter) Write(p []byte) (n int, err error) {
tw.inSequence = true tw.inSequence = true
// indicates end of "normal sequence", write whatever you have so far // indicates end of "normal sequence", write whatever you have so far
if len(p[start:current]) > 0 { if len(p[start:current]) > 0 {
nw, err := tw.emulator.WriteChars(tw.wrappedWriter, p[start:current]) nw, err := tw.emulator.WriteChars(tw.fd, tw.wrappedWriter, p[start:current])
totalWritten += nw totalWritten += nw
if err != nil { if err != nil {
return totalWritten, err return totalWritten, err
@ -126,7 +128,7 @@ func (tw *terminalWriter) Write(p []byte) (n int, err error) {
if !tw.inSequence { if !tw.inSequence {
// assumption is that we can't be inside sequence and therefore command should be empty // assumption is that we can't be inside sequence and therefore command should be empty
if len(p[start:]) > 0 { if len(p[start:]) > 0 {
nw, err := tw.emulator.WriteChars(tw.wrappedWriter, p[start:]) nw, err := tw.emulator.WriteChars(tw.fd, tw.wrappedWriter, p[start:])
totalWritten += nw totalWritten += nw
if err != nil { if err != nil {
return totalWritten, err return totalWritten, err
@ -148,7 +150,7 @@ func (tr *terminalReader) Read(p []byte) (n int, err error) {
if nil == tr.emulator { if nil == tr.emulator {
return tr.readFromWrappedReader(p) return tr.readFromWrappedReader(p)
} }
return tr.emulator.ReadChars(tr.wrappedReader, p) return tr.emulator.ReadChars(tr.fd, tr.wrappedReader, p)
} }
// Close the underlying stream // Close the underlying stream

View file

@ -71,21 +71,21 @@ func (mt *mockTerminal) record(operation int, data []byte) {
mt.OutputCommandSequence = append(mt.OutputCommandSequence, op) mt.OutputCommandSequence = append(mt.OutputCommandSequence, op)
} }
func (mt *mockTerminal) HandleOutputCommand(command []byte) (n int, err error) { func (mt *mockTerminal) HandleOutputCommand(fd uintptr, command []byte) (n int, err error) {
mt.record(COMMAND_OPERATION, command) mt.record(COMMAND_OPERATION, command)
return len(command), nil return len(command), nil
} }
func (mt *mockTerminal) HandleInputSequence(command []byte) (n int, err error) { func (mt *mockTerminal) HandleInputSequence(fd uintptr, command []byte) (n int, err error) {
return 0, nil return 0, nil
} }
func (mt *mockTerminal) WriteChars(w io.Writer, p []byte) (n int, err error) { func (mt *mockTerminal) WriteChars(fd uintptr, w io.Writer, p []byte) (n int, err error) {
mt.record(WRITE_OPERATION, p) mt.record(WRITE_OPERATION, p)
return len(p), nil return len(p), nil
} }
func (mt *mockTerminal) ReadChars(w io.Reader, p []byte) (n int, err error) { func (mt *mockTerminal) ReadChars(fd uintptr, w io.Reader, p []byte) (n int, err error) {
return len(p), nil return len(p), nil
} }