1// +build solaris
2
3// Copyright 2017 The TCell Authors
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use file except in compliance with the License.
7// You may obtain a copy of the license at
8//
9//    http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17package tcell
18
19import (
20	"os"
21	"os/signal"
22	"syscall"
23
24	"golang.org/x/sys/unix"
25)
26
27type termiosPrivate struct {
28	tio *unix.Termios
29}
30
31const (
32	// These are for missing CBAUDEXT and CIBAUDEXT.
33	// The values are fixed for Solaris and illumos, and cannot ever
34	// change without breaking applications.
35	cBaudExt  = 0x200000
36	ciBaudExt = 0x400000
37)
38
39// getbaud is sort of cfgetospeed, but in Go.
40func getbaud(tios *unix.Termios) int {
41	// First we mask off the rate by looking at the Cflag.
42	bval := tios.Cflag & unix.CBAUD
43	if (tios.Cflag & cBaudExt) != 0 {
44		bval += unix.CBAUD + 1
45	}
46
47	// This gives us the appropriate BXXX value, so convert
48	switch bval {
49	case unix.B0:
50		return 0
51	case unix.B50:
52		return 50
53	case unix.B75:
54		return 75
55	case unix.B110:
56		return 110
57	case unix.B134:
58		return 134
59	case unix.B150:
60		return 150
61	case unix.B200:
62		return 200
63	case unix.B300:
64		return 300
65	case unix.B600:
66		return 600
67	case unix.B1200:
68		return 1200
69	case unix.B1800:
70		return 1800
71	case unix.B2400:
72		return 2400
73	case unix.B4800:
74		return 4800
75	case unix.B9600:
76		return 9600
77	case unix.B19200:
78		return 19200
79	case unix.B38400:
80		return 38400
81	case unix.B57600:
82		return 57600
83	case unix.B76800:
84		return 76800
85	case unix.B115200:
86		return 115200
87	case unix.B153600:
88		return 153600
89	case unix.B230400:
90		return 230400
91	case unix.B307200:
92		return 307200
93	case unix.B460800:
94		return 460800
95	case unix.B921600:
96		return 921600
97	}
98	return 0
99}
100
101func (t *tScreen) termioInit() error {
102	var e error
103	var raw *unix.Termios
104	var tio *unix.Termios
105
106	if t.in, e = os.OpenFile("/dev/tty", os.O_RDONLY, 0); e != nil {
107		goto failed
108	}
109	if t.out, e = os.OpenFile("/dev/tty", os.O_WRONLY, 0); e != nil {
110		goto failed
111	}
112
113	tio, e = unix.IoctlGetTermios(int(t.out.Fd()), unix.TCGETS)
114	if e != nil {
115		goto failed
116	}
117
118	t.tiosp = &termiosPrivate{tio: tio}
119	t.baud = getbaud(tio)
120
121	// make a local copy, to make it raw
122	raw = &unix.Termios{
123		Cflag: tio.Cflag,
124		Oflag: tio.Oflag,
125		Iflag: tio.Iflag,
126		Lflag: tio.Lflag,
127		Cc:    tio.Cc,
128	}
129
130	raw.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.INLCR |
131		unix.IGNCR | unix.ICRNL | unix.IXON)
132	raw.Oflag &^= unix.OPOST
133	raw.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN)
134	raw.Cflag &^= (unix.CSIZE | unix.PARENB)
135	raw.Cflag |= unix.CS8
136
137	// This is setup for blocking reads.  In the past we attempted to
138	// use non-blocking reads, but now a separate input loop and timer
139	// copes with the problems we had on some systems (BSD/Darwin)
140	// where close hung forever.
141	raw.Cc[unix.VMIN] = 1
142	raw.Cc[unix.VTIME] = 0
143
144	e = unix.IoctlSetTermios(int(t.out.Fd()), unix.TCSETS, raw)
145	if e != nil {
146		goto failed
147	}
148
149	signal.Notify(t.sigwinch, syscall.SIGWINCH)
150
151	if w, h, e := t.getWinSize(); e == nil && w != 0 && h != 0 {
152		t.cells.Resize(w, h)
153	}
154
155	return nil
156
157failed:
158	if t.in != nil {
159		t.in.Close()
160	}
161	if t.out != nil {
162		t.out.Close()
163	}
164	return e
165}
166
167func (t *tScreen) termioFini() {
168
169	signal.Stop(t.sigwinch)
170
171	<-t.indoneq
172
173	if t.out != nil && t.tiosp != nil {
174		unix.IoctlSetTermios(int(t.out.Fd()), unix.TCSETSF, t.tiosp.tio)
175		t.out.Close()
176	}
177	if t.in != nil {
178		t.in.Close()
179	}
180}
181
182func (t *tScreen) getWinSize() (int, int, error) {
183	wsz, err := unix.IoctlGetWinsize(int(t.out.Fd()), unix.TIOCGWINSZ)
184	if err != nil {
185		return -1, -1, err
186	}
187	return int(wsz.Col), int(wsz.Row), nil
188}
189