nt

A sensible note-taking program
git clone git://git.laack.co/nt.git
Log | Files | Refs | README

term_unix.go (2396B)


      1 // Copyright 2019 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
      6 
      7 package term
      8 
      9 import (
     10 	"golang.org/x/sys/unix"
     11 )
     12 
     13 type state struct {
     14 	termios unix.Termios
     15 }
     16 
     17 func isTerminal(fd int) bool {
     18 	_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
     19 	return err == nil
     20 }
     21 
     22 func makeRaw(fd int) (*State, error) {
     23 	termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
     24 	if err != nil {
     25 		return nil, err
     26 	}
     27 
     28 	oldState := State{state{termios: *termios}}
     29 
     30 	// This attempts to replicate the behaviour documented for cfmakeraw in
     31 	// the termios(3) manpage.
     32 	termios.Iflag &^= unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON
     33 	termios.Oflag &^= unix.OPOST
     34 	termios.Lflag &^= unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN
     35 	termios.Cflag &^= unix.CSIZE | unix.PARENB
     36 	termios.Cflag |= unix.CS8
     37 	termios.Cc[unix.VMIN] = 1
     38 	termios.Cc[unix.VTIME] = 0
     39 	if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, termios); err != nil {
     40 		return nil, err
     41 	}
     42 
     43 	return &oldState, nil
     44 }
     45 
     46 func getState(fd int) (*State, error) {
     47 	termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
     48 	if err != nil {
     49 		return nil, err
     50 	}
     51 
     52 	return &State{state{termios: *termios}}, nil
     53 }
     54 
     55 func restore(fd int, state *State) error {
     56 	return unix.IoctlSetTermios(fd, ioctlWriteTermios, &state.termios)
     57 }
     58 
     59 func getSize(fd int) (width, height int, err error) {
     60 	ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
     61 	if err != nil {
     62 		return 0, 0, err
     63 	}
     64 	return int(ws.Col), int(ws.Row), nil
     65 }
     66 
     67 // passwordReader is an io.Reader that reads from a specific file descriptor.
     68 type passwordReader int
     69 
     70 func (r passwordReader) Read(buf []byte) (int, error) {
     71 	return unix.Read(int(r), buf)
     72 }
     73 
     74 func readPassword(fd int) ([]byte, error) {
     75 	termios, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
     76 	if err != nil {
     77 		return nil, err
     78 	}
     79 
     80 	newState := *termios
     81 	newState.Lflag &^= unix.ECHO
     82 	newState.Lflag |= unix.ICANON | unix.ISIG
     83 	newState.Iflag |= unix.ICRNL
     84 	if err := unix.IoctlSetTermios(fd, ioctlWriteTermios, &newState); err != nil {
     85 		return nil, err
     86 	}
     87 
     88 	defer unix.IoctlSetTermios(fd, ioctlWriteTermios, termios)
     89 
     90 	return readPasswordLine(passwordReader(fd))
     91 }