termios.go

  1//go:build darwin || netbsd || freebsd || openbsd || linux || dragonfly || solaris
  2// +build darwin netbsd freebsd openbsd linux dragonfly solaris
  3
  4package termios
  5
  6import (
  7	"syscall"
  8
  9	"golang.org/x/sys/unix"
 10)
 11
 12// SetWinsize sets window size for an fd from a Winsize.
 13func SetWinsize(fd int, w *unix.Winsize) error {
 14	return unix.IoctlSetWinsize(fd, ioctlSetWinSize, w)
 15}
 16
 17// GetWinsize gets window size for an fd.
 18func GetWinsize(fd int) (*unix.Winsize, error) {
 19	return unix.IoctlGetWinsize(fd, ioctlGetWinSize)
 20}
 21
 22// GetTermios gets the termios of the given fd.
 23func GetTermios(fd int) (*unix.Termios, error) {
 24	return unix.IoctlGetTermios(fd, ioctlGets)
 25}
 26
 27// SetTermios sets the given termios over the given fd's current termios.
 28func SetTermios(
 29	fd int,
 30	ispeed uint32,
 31	ospeed uint32,
 32	cc map[CC]uint8,
 33	iflag map[I]bool,
 34	oflag map[O]bool,
 35	cflag map[C]bool,
 36	lflag map[L]bool,
 37) error {
 38	term, err := unix.IoctlGetTermios(fd, ioctlGets)
 39	if err != nil {
 40		return err
 41	}
 42	setSpeed(term, ispeed, ospeed)
 43
 44	for key, value := range cc {
 45		call, ok := allCcOpts[key]
 46		if !ok {
 47			continue
 48		}
 49		term.Cc[call] = value
 50	}
 51
 52	for key, value := range iflag {
 53		mask, ok := allInputOpts[key]
 54		if ok {
 55			if value {
 56				term.Iflag |= bit(mask)
 57			} else {
 58				term.Iflag &= ^bit(mask)
 59			}
 60		}
 61	}
 62	for key, value := range oflag {
 63		mask, ok := allOutputOpts[key]
 64		if ok {
 65			if value {
 66				term.Oflag |= bit(mask)
 67			} else {
 68				term.Oflag &= ^bit(mask)
 69			}
 70		}
 71	}
 72	for key, value := range cflag {
 73		mask, ok := allControlOpts[key]
 74		if ok {
 75			if value {
 76				term.Cflag |= bit(mask)
 77			} else {
 78				term.Cflag &= ^bit(mask)
 79			}
 80		}
 81	}
 82	for key, value := range lflag {
 83		mask, ok := allLineOpts[key]
 84		if ok {
 85			if value {
 86				term.Lflag |= bit(mask)
 87			} else {
 88				term.Lflag &= ^bit(mask)
 89			}
 90		}
 91	}
 92	return unix.IoctlSetTermios(fd, ioctlSets, term)
 93}
 94
 95// CC is the termios cc field.
 96//
 97// It stores an array of special characters related to terminal I/O.
 98type CC uint8
 99
100// CC possible values.
101const (
102	INTR CC = iota
103	QUIT
104	ERASE
105	KILL
106	EOF
107	EOL
108	EOL2
109	START
110	STOP
111	SUSP
112	WERASE
113	RPRNT
114	LNEXT
115	DISCARD
116	STATUS
117	SWTCH
118	DSUSP
119	FLUSH
120)
121
122// https://www.man7.org/linux/man-pages/man3/termios.3.html
123var allCcOpts = map[CC]int{
124	INTR:    syscall.VINTR,
125	QUIT:    syscall.VQUIT,
126	ERASE:   syscall.VERASE,
127	KILL:    syscall.VQUIT,
128	EOF:     syscall.VEOF,
129	EOL:     syscall.VEOL,
130	EOL2:    syscall.VEOL2,
131	START:   syscall.VSTART,
132	STOP:    syscall.VSTOP,
133	SUSP:    syscall.VSUSP,
134	WERASE:  syscall.VWERASE,
135	RPRNT:   syscall.VREPRINT,
136	LNEXT:   syscall.VLNEXT,
137	DISCARD: syscall.VDISCARD,
138
139	// XXX: these syscalls don't exist for any OS
140	// FLUSH:  syscall.VFLUSH,
141}
142
143// Input Controls
144type I uint8
145
146// Input possible values.
147const (
148	IGNPAR I = iota
149	PARMRK
150	INPCK
151	ISTRIP
152	INLCR
153	IGNCR
154	ICRNL
155	IXON
156	IXANY
157	IXOFF
158	IMAXBEL
159	IUCLC
160)
161
162var allInputOpts = map[I]uint32{
163	IGNPAR:  syscall.IGNPAR,
164	PARMRK:  syscall.PARMRK,
165	INPCK:   syscall.INPCK,
166	ISTRIP:  syscall.ISTRIP,
167	INLCR:   syscall.INLCR,
168	IGNCR:   syscall.IGNCR,
169	ICRNL:   syscall.ICRNL,
170	IXON:    syscall.IXON,
171	IXANY:   syscall.IXANY,
172	IXOFF:   syscall.IXOFF,
173	IMAXBEL: syscall.IMAXBEL,
174}
175
176// Output Controls
177type O uint8
178
179// Output possible values.
180const (
181	OPOST O = iota
182	ONLCR
183	OCRNL
184	ONOCR
185	ONLRET
186	OLCUC
187)
188
189var allOutputOpts = map[O]uint32{
190	OPOST:  syscall.OPOST,
191	ONLCR:  syscall.ONLCR,
192	OCRNL:  syscall.OCRNL,
193	ONOCR:  syscall.ONOCR,
194	ONLRET: syscall.ONLRET,
195}
196
197// Control
198type C uint8
199
200// Control possible values.
201const (
202	CS7 C = iota
203	CS8
204	PARENB
205	PARODD
206)
207
208var allControlOpts = map[C]uint32{
209	CS7:    syscall.CS7,
210	CS8:    syscall.CS8,
211	PARENB: syscall.PARENB,
212	PARODD: syscall.PARODD,
213}
214
215// Line Controls.
216type L uint8
217
218// Line possible values.
219const (
220	ISIG L = iota
221	ICANON
222	ECHO
223	ECHOE
224	ECHOK
225	ECHONL
226	NOFLSH
227	TOSTOP
228	IEXTEN
229	ECHOCTL
230	ECHOKE
231	PENDIN
232	IUTF8
233	XCASE
234)
235
236var allLineOpts = map[L]uint32{
237	ISIG:    syscall.ISIG,
238	ICANON:  syscall.ICANON,
239	ECHO:    syscall.ECHO,
240	ECHOE:   syscall.ECHOE,
241	ECHOK:   syscall.ECHOK,
242	ECHONL:  syscall.ECHONL,
243	NOFLSH:  syscall.NOFLSH,
244	TOSTOP:  syscall.TOSTOP,
245	IEXTEN:  syscall.IEXTEN,
246	ECHOCTL: syscall.ECHOCTL,
247	ECHOKE:  syscall.ECHOKE,
248	PENDIN:  syscall.PENDIN,
249}