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