
2 May
2008
2 May
'08
9:55 a.m.
On Fri, May 2, 2008 at 12:16 AM, Donn Cavewrote: > Graham Fawcett wrote: > > > > I would like to communicate with an external, line-oriented process, > > which takes a sequence of one-line commands, each returning an > > arbitrary number of lines, and waits for another command after each > > response. So, something like: > > sendCmd :: (Handle, Handle) -> String -> IO [String] > You may need to make some compromises to get this within the realm > of the possible, if I understand your objective. > - There is no way (at least on UNIX) to know when a read has been posted > on the other end of your pipe/socket/pty/whatever... Yes, and I should have realized this. After my post, I tried writing the same program in another language, and ran into the same problems. Thanks very much for the response. I'm going to play with your example, and see if I can make it work in this case (and if not, I will still learn from studying it!). In case it's of interest, I see that E.W. Karlsen wrote a series of articles (ten years ago!) on using Haskell to manage asynchronous processes, and included an "expect-like" tool in his UniForM Workbench: http://www.informatik.uni-bremen.de/~ewk/WB.html By the way, what I'm trying to do is to interact with a Berkeley XML database; there's no existing Haskell wrapper for its API, and for this particular task the cost of writing one is too high. I was going to interact with the 'dbxml' command-line utility as a poor-man's FFI. Given the issues you've raised, instead I might use a language that has an existing DBXML interface, and call that from Haskell (e.g. Python via MissingPy). Thanks again, Graham > So you can't tell in this > way when the external process has sent the last of the arbitrary number > of > lines and is now waiting for another command. If you have another way to > know, or it doesn't really matter, then fine. > > - The vast majority of `line-oriented' software are actually going to block > buffer > their output when writing to a pipe, because that's what C I/O does. If > you're > lucky, the program you're dealing with here will flush its output before > it reads, > but if it doesn't, you're hosed - there isn't any way to talk to this > program > `interactively' on a pipe. In this case, you need a pseudotty device, a > sort of > pipe that supports tty device ioctls. > > - Buffering on your side of the I/O is of course also worse than useless. > > I see the GHC 6.8 library supports pseudottys, so for general amusement > I submit below a small demonstration program. Unfortunately it doesn't > entirely work. The pseudotty works, but I'm unable to turn off ECHO on the > slave. So each master line yields two slave lines, and my program expects > only one and gets behind on that account. So the command has to include > its own "stty -echo". The commented lines attempt to turn of ECHO, but on > MacOS X that causes the program to fail mysteriously. > > Donn Cave, donn@avvanta.com > -------------------------------------------------- > import System.Posix.Terminal (TerminalMode(..), TerminalState(..), > withoutMode, getTerminalAttributes, setTerminalAttributes, > openPseudoTerminal, getSlaveTerminalName) > import System (getArgs) > import System.Posix.Types (Fd, ProcessID) > import System.Posix.Process (forkProcess, executeFile) > import System.Posix.IO (stdInput, stdOutput, closeFd, dupTo, fdWrite, > fdRead) > > pchild :: Fd -> IO () -> IO () > pchild slaveFd exec = do > dupTo slaveFd stdInput > dupTo slaveFd stdOutput > closeFd slaveFd > exec > > ptyOpen :: IO () -> IO (ProcessID, Fd) > ptyOpen exec = do > (master, slave) <- openPseudoTerminal > -- tc <- getTerminalAttributes slave > -- let tc = withoutMode tc EchoLF > -- setTerminalAttributes slave tc WhenDrained > pid <- forkProcess (pchild slave exec) > closeFd slave > return (pid, master) > > ioact p0 p1 m0 m1 = do > (d, n) <- fdRead m0 512 > fdWrite p1 d > (e, n) <- fdRead p0 512 > fdWrite m1 e > ioact p0 p1 m0 m1 > > main = do > (cmd:args) <- getArgs > (pid, fd) <- ptyOpen (executeFile cmd True args Nothing) > ioact fd fd stdInput stdOutput > > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe >