[project @ 1999-01-14 18:18:45 by sof]
[ghc-hetmet.git] / ghc / lib / posix / PosixTTY.lhs
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1995-1996
3 %
4 \section[PosixTTY]{Haskell 1.3 POSIX Device-Specific Functions}
5
6 \begin{code}
7 module PosixTTY (
8     BaudRate(..),
9     ControlCharacter(..),
10     FlowAction(..),
11     QueueSelector(..),
12     TerminalAttributes,
13     TerminalMode(..),
14     TerminalState(..),
15     bitsPerByte,
16     controlChar,
17     controlFlow,
18     discardData,
19     drainOutput,
20     getTerminalAttributes,
21     getTerminalProcessGroupID,
22     inputSpeed,
23     inputTime,
24     minInput,
25     outputSpeed,
26     sendBreak,
27     setTerminalAttributes,
28     setTerminalProcessGroupID,
29     terminalMode,
30     withBits,
31     withCC,
32     withInputSpeed,
33     withMinInput,
34     withMode,
35     withOutputSpeed,
36     withTime,
37     withoutCC,
38     withoutMode
39     ) where
40
41 import GlaExts
42 import IOExts ( unsafePerformIO )
43
44 import IO
45 import Foreign
46
47 import PosixUtil
48 import PosixErr
49 import CString  ( freeze, allocChars )
50
51 \end{code}
52
53 \begin{code}
54 type TerminalAttributes = ByteArray Int
55
56 data TerminalMode = InterruptOnBreak
57                   | MapCRtoLF
58                   | IgnoreBreak
59                   | IgnoreCR
60                   | IgnoreParityErrors
61                   | MapLFtoCR
62                   | CheckParity
63                   | StripHighBit
64                   | StartStopInput
65                   | StartStopOutput
66                   | MarkParityErrors
67                   | ProcessOutput
68                   | LocalMode
69                   | ReadEnable
70                   | TwoStopBits
71                   | HangupOnClose
72                   | EnableParity
73                   | OddParity
74                   | EnableEcho
75                   | EchoErase
76                   | EchoKill
77                   | EchoLF
78                   | ProcessInput
79                   | ExtendedFunctions
80                   | KeyboardInterrupts
81                   | NoFlushOnInterrupt
82                   | BackgroundWriteInterrupt
83
84 withoutMode :: TerminalAttributes -> TerminalMode -> TerminalAttributes
85 withoutMode termios InterruptOnBreak = clearInputFlag ``BRKINT'' termios
86 withoutMode termios MapCRtoLF = clearInputFlag ``ICRNL'' termios
87 withoutMode termios IgnoreBreak = clearInputFlag ``IGNBRK'' termios
88 withoutMode termios IgnoreCR = clearInputFlag ``IGNCR'' termios
89 withoutMode termios IgnoreParityErrors = clearInputFlag ``IGNPAR'' termios
90 withoutMode termios MapLFtoCR = clearInputFlag ``INLCR'' termios
91 withoutMode termios CheckParity = clearInputFlag ``INPCK'' termios
92 withoutMode termios StripHighBit = clearInputFlag ``ISTRIP'' termios
93 withoutMode termios StartStopInput = clearInputFlag ``IXOFF'' termios
94 withoutMode termios StartStopOutput = clearInputFlag ``IXON'' termios
95 withoutMode termios MarkParityErrors = clearInputFlag ``PARMRK'' termios
96 withoutMode termios ProcessOutput = unsafePerformIO $
97     allocChars ``sizeof(struct termios)''           >>= \ bytes ->
98     _casm_ ``*(struct termios *)%0 = *(struct termios *)%1;
99              ((struct termios *)%0)->c_oflag &= ~OPOST;'' bytes termios
100                                                     >>= \ () ->
101     freeze bytes
102 withoutMode termios LocalMode = clearControlFlag ``CLOCAL'' termios
103 withoutMode termios ReadEnable = clearControlFlag ``CREAD'' termios
104 withoutMode termios TwoStopBits = clearControlFlag ``CSTOPB'' termios
105 withoutMode termios HangupOnClose = clearControlFlag ``HUPCL'' termios
106 withoutMode termios EnableParity = clearControlFlag ``PARENB'' termios
107 withoutMode termios OddParity = clearControlFlag ``PARODD'' termios
108 withoutMode termios EnableEcho = clearLocalFlag ``ECHO'' termios
109 withoutMode termios EchoErase = clearLocalFlag ``ECHOE'' termios
110 withoutMode termios EchoKill = clearLocalFlag ``ECHOK'' termios
111 withoutMode termios EchoLF = clearLocalFlag ``ECHONL'' termios
112 withoutMode termios ProcessInput = clearLocalFlag ``ICANON'' termios
113 withoutMode termios ExtendedFunctions = clearLocalFlag ``IEXTEN'' termios
114 withoutMode termios KeyboardInterrupts = clearLocalFlag ``ISIG'' termios
115 withoutMode termios NoFlushOnInterrupt = setLocalFlag ``NOFLSH'' termios
116 withoutMode termios BackgroundWriteInterrupt = clearLocalFlag ``TOSTOP'' termios
117
118 withMode :: TerminalAttributes -> TerminalMode -> TerminalAttributes
119 withMode termios InterruptOnBreak = setInputFlag ``BRKINT'' termios
120 withMode termios MapCRtoLF = setInputFlag ``ICRNL'' termios
121 withMode termios IgnoreBreak = setInputFlag ``IGNBRK'' termios
122 withMode termios IgnoreCR = setInputFlag ``IGNCR'' termios
123 withMode termios IgnoreParityErrors = setInputFlag ``IGNPAR'' termios
124 withMode termios MapLFtoCR = setInputFlag ``INLCR'' termios
125 withMode termios CheckParity = setInputFlag ``INPCK'' termios
126 withMode termios StripHighBit = setInputFlag ``ISTRIP'' termios
127 withMode termios StartStopInput = setInputFlag ``IXOFF'' termios
128 withMode termios StartStopOutput = setInputFlag ``IXON'' termios
129 withMode termios MarkParityErrors = setInputFlag ``PARMRK'' termios
130 withMode termios ProcessOutput = unsafePerformIO $ do
131     bytes <- allocChars ``sizeof(struct termios)''
132     _casm_ ``*(struct termios *)%0 = *(struct termios *)%1;
133              ((struct termios *)%0)->c_oflag |= OPOST;'' bytes termios
134     freeze bytes
135 withMode termios LocalMode = setControlFlag ``CLOCAL'' termios
136 withMode termios ReadEnable = setControlFlag ``CREAD'' termios
137 withMode termios TwoStopBits = setControlFlag ``CSTOPB'' termios
138 withMode termios HangupOnClose = setControlFlag ``HUPCL'' termios
139 withMode termios EnableParity = setControlFlag ``PARENB'' termios
140 withMode termios OddParity = setControlFlag ``PARODD'' termios
141 withMode termios EnableEcho = setLocalFlag ``ECHO'' termios
142 withMode termios EchoErase = setLocalFlag ``ECHOE'' termios
143 withMode termios EchoKill = setLocalFlag ``ECHOK'' termios
144 withMode termios EchoLF = setLocalFlag ``ECHONL'' termios
145 withMode termios ProcessInput = setLocalFlag ``ICANON'' termios
146 withMode termios ExtendedFunctions = setLocalFlag ``IEXTEN'' termios
147 withMode termios KeyboardInterrupts = setLocalFlag ``ISIG'' termios
148 withMode termios NoFlushOnInterrupt = clearLocalFlag ``NOFLSH'' termios
149 withMode termios BackgroundWriteInterrupt = setLocalFlag ``TOSTOP'' termios
150
151 terminalMode :: TerminalMode -> TerminalAttributes -> Bool
152 terminalMode InterruptOnBreak = testInputFlag ``BRKINT''
153 terminalMode MapCRtoLF = testInputFlag ``ICRNL''
154 terminalMode IgnoreBreak = testInputFlag ``IGNBRK''
155 terminalMode IgnoreCR = testInputFlag ``IGNCR''
156 terminalMode IgnoreParityErrors = testInputFlag ``IGNPAR''
157 terminalMode MapLFtoCR = testInputFlag ``INLCR''
158 terminalMode CheckParity = testInputFlag ``INPCK''
159 terminalMode StripHighBit = testInputFlag ``ISTRIP''
160 terminalMode StartStopInput = testInputFlag ``IXOFF''
161 terminalMode StartStopOutput = testInputFlag ``IXON''
162 terminalMode MarkParityErrors = testInputFlag ``PARMRK''
163 terminalMode ProcessOutput = \ termios -> unsafePerformIO $
164     _casm_ ``%r = ((struct termios *)%0)->c_oflag & OPOST;'' termios
165                                                     >>= \ (W# flags#) ->
166     return (flags# `neWord#` int2Word# 0#)
167 terminalMode LocalMode = testControlFlag ``CLOCAL''
168 terminalMode ReadEnable = testControlFlag ``CREAD''
169 terminalMode TwoStopBits = testControlFlag ``CSTOPB''
170 terminalMode HangupOnClose = testControlFlag ``HUPCL''
171 terminalMode EnableParity = testControlFlag ``PARENB''
172 terminalMode OddParity = testControlFlag ``PARODD''
173 terminalMode EnableEcho = testLocalFlag ``ECHO''
174 terminalMode EchoErase = testLocalFlag ``ECHOE''
175 terminalMode EchoKill = testLocalFlag ``ECHOK''
176 terminalMode EchoLF = testLocalFlag ``ECHONL''
177 terminalMode ProcessInput = testLocalFlag ``ICANON''
178 terminalMode ExtendedFunctions = testLocalFlag ``IEXTEN''
179 terminalMode KeyboardInterrupts = testLocalFlag ``ISIG''
180 terminalMode NoFlushOnInterrupt = not . testLocalFlag ``NOFLSH''
181 terminalMode BackgroundWriteInterrupt = testLocalFlag ``TOSTOP''
182
183 bitsPerByte :: TerminalAttributes -> Int
184 bitsPerByte termios = unsafePerformIO $ do
185     w <- _casm_ ``%r = ((struct termios *)%0)->c_cflag & CSIZE;'' termios
186     return (word2Bits w)
187   where
188     word2Bits :: Word -> Int
189     word2Bits x =
190         if x == ``CS5'' then 5
191         else if x == ``CS6'' then 6
192         else if x == ``CS7'' then 7
193         else if x == ``CS8'' then 8
194         else 0
195
196 withBits :: TerminalAttributes -> Int -> TerminalAttributes
197 withBits termios bits = unsafePerformIO $ do
198     bytes <- allocChars ``sizeof(struct termios)''
199     _casm_ ``*(struct termios *)%0 = *(struct termios *)%1;
200              ((struct termios *)%0)->c_cflag =
201              (((struct termios *)%1)->c_cflag & ~CSIZE) | %2;''
202         bytes termios (mask bits)
203     freeze bytes
204   where
205     mask :: Int -> Word
206     mask 5 = ``CS5''
207     mask 6 = ``CS6''
208     mask 7 = ``CS7''
209     mask 8 = ``CS8''
210     mask _ = error "withBits bit value out of range [5..8]"
211
212 data ControlCharacter = EndOfFile
213                       | EndOfLine
214                       | Erase
215                       | Interrupt
216                       | Kill
217                       | Quit
218                       | Suspend
219                       | Start
220                       | Stop
221
222 controlChar :: TerminalAttributes -> ControlCharacter -> Maybe Char
223 controlChar termios cc = unsafePerformIO $ do
224     val <- _casm_ ``%r = ((struct termios *)%0)->c_cc[%1];''
225                   termios (cc2Word cc)
226     if val == (``_POSIX_VDISABLE''::Int)
227        then return Nothing
228        else return (Just (toEnum val))
229
230 withCC :: TerminalAttributes
231        -> (ControlCharacter, Char)
232        -> TerminalAttributes
233 withCC termios (cc, c) = unsafePerformIO $ do
234     bytes <- allocChars ``sizeof(struct termios)''
235     _casm_ ``*(struct termios *)%0 = *(struct termios *)%1;
236              ((struct termios *)%0)->c_cc[%2] = %3;''
237         bytes termios (cc2Word cc) c
238     freeze bytes
239
240 withoutCC :: TerminalAttributes
241           -> ControlCharacter
242           -> TerminalAttributes
243 withoutCC termios cc = unsafePerformIO $ do
244     bytes <- allocChars ``sizeof(struct termios)''
245     _casm_ ``*(struct termios *)%0 = *(struct termios *)%1;
246              ((struct termios *)%0)->c_cc[%2] = _POSIX_VDISABLE;''
247         bytes termios (cc2Word cc)
248     freeze bytes
249
250 inputTime :: TerminalAttributes -> Int
251 inputTime termios = unsafePerformIO $ do
252     _casm_ ``%r = ((struct termios *)%0)->c_cc[VTIME];'' termios
253
254 withTime :: TerminalAttributes -> Int -> TerminalAttributes
255 withTime termios time = unsafePerformIO $ do
256     bytes <- allocChars ``sizeof(struct termios)''
257     _casm_ ``*(struct termios *)%0 = *(struct termios *)%1;
258              ((struct termios *)%0)->c_cc[VTIME] = %2;'' bytes termios time
259     freeze bytes
260
261 minInput :: TerminalAttributes -> Int
262 minInput termios = unsafePerformIO $ do
263     _casm_ ``%r = ((struct termios *)%0)->c_cc[VMIN];'' termios
264
265 withMinInput :: TerminalAttributes -> Int -> TerminalAttributes
266 withMinInput termios count = unsafePerformIO $ do
267     bytes <- allocChars ``sizeof(struct termios)''
268     _casm_ ``*(struct termios *)%0 = *(struct termios *)%1;
269              ((struct termios *)%0)->c_cc[VMIN] = %2;'' bytes termios count
270     freeze bytes
271
272 data BaudRate = B0
273               | B50
274               | B75
275               | B110
276               | B134
277               | B150
278               | B200
279               | B300
280               | B600
281               | B1200
282               | B1800
283               | B2400
284               | B4800
285               | B9600
286               | B19200
287               | B38400
288
289 inputSpeed :: TerminalAttributes -> BaudRate
290 inputSpeed termios = unsafePerformIO $ do
291     w <-_casm_ ``%r = cfgetispeed((struct termios *)%0);'' termios
292     return (word2Baud w)
293
294 withInputSpeed :: TerminalAttributes -> BaudRate -> TerminalAttributes
295 withInputSpeed termios br = unsafePerformIO $ do
296     bytes <- allocChars ``sizeof(struct termios)''
297     _casm_ ``*(struct termios *)%0 = *(struct termios *)%1;
298              cfsetispeed((struct termios *)%0, %2);'' bytes termios (baud2Word br)
299     freeze bytes
300
301 outputSpeed :: TerminalAttributes -> BaudRate
302 outputSpeed termios = unsafePerformIO $ do
303     w <- _casm_ ``%r = cfgetospeed((struct termios *)%0);'' termios
304     return (word2Baud w)
305
306 withOutputSpeed :: TerminalAttributes -> BaudRate -> TerminalAttributes
307 withOutputSpeed termios br = unsafePerformIO $ do
308     bytes <- allocChars ``sizeof(struct termios)''
309     _casm_ ``*(struct termios *)%0 = *(struct termios *)%1;
310              cfsetospeed((struct termios *)%0, %2);'' bytes termios (baud2Word br)
311     freeze bytes
312
313 getTerminalAttributes :: Fd -> IO TerminalAttributes
314 getTerminalAttributes (FD# fd) = do
315     bytes <- allocChars ``sizeof(struct termios)''
316     rc <- _casm_ ``%r = tcgetattr(%0,(struct termios *)%1);'' fd bytes
317     if rc /= ((-1)::Int)
318        then freeze bytes
319        else syserr "getTerminalAttributes"
320
321 data TerminalState = Immediately
322                    | WhenDrained
323                    | WhenFlushed
324
325 setTerminalAttributes :: Fd
326                       -> TerminalAttributes
327                       -> TerminalState
328                       -> IO ()
329 setTerminalAttributes (FD# fd) termios state = do
330     rc <- _casm_ ``%r = tcsetattr(%0,%1,(struct termios *)%2);''
331                  fd (state2Int state) termios
332     if rc /= ((-1)::Int)
333        then return ()
334        else syserr "setTerminalAttributes"
335   where
336     state2Int :: TerminalState -> Int
337     state2Int Immediately = ``TCSANOW''
338     state2Int WhenDrained = ``TCSADRAIN''
339     state2Int WhenFlushed = ``TCSAFLUSH''
340
341 sendBreak :: Fd -> Int -> IO ()
342 sendBreak (FD# fd) duration =
343     nonzero_error (_ccall_ tcsendbreak fd duration) "sendBreak"
344
345 drainOutput :: Fd -> IO ()
346 drainOutput (FD# fd) =
347     nonzero_error (_ccall_ tcdrain fd) "drainOutput"
348
349 data QueueSelector = InputQueue
350                    | OutputQueue
351                    | BothQueues
352
353 discardData :: Fd -> QueueSelector -> IO ()
354 discardData (FD# fd) queue =
355     minusone_error (_ccall_ tcflush fd (queue2Int queue)) "discardData"
356   where
357     queue2Int :: QueueSelector -> Int
358     queue2Int InputQueue  = ``TCIFLUSH''
359     queue2Int OutputQueue = ``TCOFLUSH''
360     queue2Int BothQueues  = ``TCIOFLUSH''
361
362 data FlowAction = SuspendOutput
363                 | RestartOutput
364                 | TransmitStop
365                 | TransmitStart
366
367 controlFlow :: Fd -> FlowAction -> IO ()
368 controlFlow (FD# fd) action =
369     minusone_error (_ccall_ tcflow fd (action2Int action)) "controlFlow"
370   where
371     action2Int :: FlowAction -> Int
372     action2Int SuspendOutput = ``TCOOFF''
373     action2Int RestartOutput = ``TCOON''
374     action2Int TransmitStop  = ``TCIOFF''
375     action2Int TransmitStart = ``TCION''
376
377 getTerminalProcessGroupID :: Fd -> IO ProcessGroupID
378 getTerminalProcessGroupID (FD# fd) = do
379     pgid <- _ccall_ tcgetpgrp fd
380     if pgid /= ((-1)::Int)
381        then return pgid
382        else syserr "getTerminalProcessGroupID"
383
384 setTerminalProcessGroupID :: Fd -> ProcessGroupID -> IO ()
385 setTerminalProcessGroupID (FD# fd) pgid =
386     nonzero_error (_ccall_ tcsetpgrp fd pgid) "setTerminalProcessGroupID"
387
388 \end{code}
389
390 Local utility functions
391
392 \begin{code}
393
394 -- Convert Haskell ControlCharacter to Int
395
396 cc2Word :: ControlCharacter -> Word
397 cc2Word EndOfFile = ``VEOF''
398 cc2Word EndOfLine = ``VEOL''
399 cc2Word Erase     = ``VERASE''
400 cc2Word Interrupt = ``VINTR''
401 cc2Word Kill      = ``VKILL''
402 cc2Word Quit      = ``VQUIT''
403 cc2Word Suspend   = ``VSUSP''
404 cc2Word Start     = ``VSTART''
405 cc2Word Stop      = ``VSTOP''
406
407 -- Convert Haskell BaudRate to unsigned integral type (Word)
408
409 baud2Word :: BaudRate -> Word
410 baud2Word B0 = ``B0''
411 baud2Word B50 = ``B50''
412 baud2Word B75 = ``B75''
413 baud2Word B110 = ``B110''
414 baud2Word B134 = ``B134''
415 baud2Word B150 = ``B150''
416 baud2Word B200 = ``B200''
417 baud2Word B300 = ``B300''
418 baud2Word B600 = ``B600''
419 baud2Word B1200 = ``B1200''
420 baud2Word B1800 = ``B1800''
421 baud2Word B2400 = ``B2400''
422 baud2Word B4800 = ``B4800''
423 baud2Word B9600 = ``B9600''
424 baud2Word B19200 = ``B19200''
425 baud2Word B38400 = ``B38400''
426
427 -- And convert a word back to a baud rate
428 -- We really need some cpp macros here.
429
430 word2Baud :: Word -> BaudRate
431 word2Baud x =
432     if x == ``B0'' then B0
433     else if x == ``B50'' then B50
434     else if x == ``B75'' then B75
435     else if x == ``B110'' then B110
436     else if x == ``B134'' then B134
437     else if x == ``B150'' then B150
438     else if x == ``B200'' then B200
439     else if x == ``B300'' then B300
440     else if x == ``B600'' then B600
441     else if x == ``B1200'' then B1200
442     else if x == ``B1800'' then B1800
443     else if x == ``B2400'' then B2400
444     else if x == ``B4800'' then B4800
445     else if x == ``B9600'' then B9600
446     else if x == ``B19200'' then B19200
447     else if x == ``B38400'' then B38400
448     else error "unknown baud rate"
449
450 -- Clear termios i_flag
451
452 clearInputFlag :: Word -> TerminalAttributes -> TerminalAttributes
453 clearInputFlag flag termios = unsafePerformIO $ do
454     bytes <- allocChars ``sizeof(struct termios)''
455     _casm_ ``*(struct termios *)%0 = *(struct termios *)%1;
456              ((struct termios *)%0)->c_iflag &= ~%2;'' bytes termios flag
457     freeze bytes
458
459 -- Set termios i_flag
460
461 setInputFlag :: Word -> TerminalAttributes -> TerminalAttributes
462 setInputFlag flag termios = unsafePerformIO $ do
463     bytes <- allocChars ``sizeof(struct termios)''
464     _casm_ ``*(struct termios *)%0 = *(struct termios *)%1;
465              ((struct termios *)%0)->c_iflag |= %2;'' bytes termios flag
466     freeze bytes
467
468 -- Examine termios i_flag
469
470 testInputFlag :: Word -> TerminalAttributes -> Bool
471 testInputFlag flag termios = unsafePerformIO $
472     _casm_ ``%r = ((struct termios *)%0)->c_iflag & %1;'' termios flag
473                                                     >>= \ (W# flags#) ->
474     return (flags# `neWord#` int2Word# 0#)
475
476 -- Clear termios c_flag
477
478 clearControlFlag :: Word -> TerminalAttributes -> TerminalAttributes
479 clearControlFlag flag termios = unsafePerformIO $ do
480     bytes <- allocChars ``sizeof(struct termios)''
481     _casm_ ``*(struct termios *)%0 = *(struct termios *)%1;
482              ((struct termios *)%0)->c_cflag &= ~%2;'' bytes termios flag
483     freeze bytes
484
485 -- Set termios c_flag
486
487 setControlFlag :: Word -> TerminalAttributes -> TerminalAttributes
488 setControlFlag flag termios = unsafePerformIO $ do
489     bytes <- allocChars ``sizeof(struct termios)''
490     _casm_ ``*(struct termios *)%0 = *(struct termios *)%1;
491              ((struct termios *)%0)->c_cflag |= %2;'' bytes termios flag
492     freeze bytes
493
494 -- Examine termios c_flag
495
496 testControlFlag :: Word -> TerminalAttributes -> Bool
497 testControlFlag flag termios = unsafePerformIO $
498     _casm_ ``%r = ((struct termios *)%0)->c_cflag & %1;'' termios flag
499                                                     >>= \ (W# flags#) ->
500     return (flags# `neWord#` int2Word# 0#)
501
502 -- Clear termios l_flag
503
504 clearLocalFlag :: Word -> TerminalAttributes -> TerminalAttributes
505 clearLocalFlag flag termios = unsafePerformIO $ do
506     bytes <- allocChars ``sizeof(struct termios)''
507     _casm_ ``*(struct termios *)%0 = *(struct termios *)%1;
508              ((struct termios *)%0)->c_lflag &= ~%2;'' bytes termios flag
509     freeze bytes
510
511 -- Set termios l_flag
512
513 setLocalFlag :: Word -> TerminalAttributes -> TerminalAttributes
514 setLocalFlag flag termios = unsafePerformIO $ do
515     bytes <- allocChars ``sizeof(struct termios)''
516     _casm_ ``*(struct termios *)%0 = *(struct termios *)%1;
517              ((struct termios *)%0)->c_lflag |= %2;'' bytes termios flag
518     freeze bytes
519
520 -- Examine termios l_flag
521
522 testLocalFlag :: Word -> TerminalAttributes -> Bool
523 testLocalFlag flag termios = unsafePerformIO $
524     _casm_ ``%r = ((struct termios *)%0)->c_iflag & %1;'' termios flag
525                                                     >>= \ (W# flags#) ->
526     return (flags# `neWord#` int2Word# 0#)
527 \end{code}