Pipe-1.0: Process piping library

MaintainerMatti Niemenmaa <matti.niemenmaa+web@iki.fi>



Operations for piping data through multiple processes.

pipe is the most general function, with filePipe and 'pipe\'' provided for convenience purposes. For the common case of piping between Strings, the pipeString wrapper and the word8ToString and stringToWord8 helpers are included.

Whenever specifying a path to a process, explicitly specifying the current directory is recommended for portability. That is: use "./foo" instead of "foo", for instance.

On Windows, appending ".exe" to process paths is attempted if the invocation fails.



filePipe :: [(FilePath, [String])] -> FilePath -> FilePath -> IO ()Source

Pipes the contents of the first file to the second file through all the programs named.

The working directory used is the directory component of the path to the first file.

class Tap a whereSource

From a Tap, data up to the requested amount flows into a Ptr. The exact amount of 'Word8'\'s that flowed is returned. The requested amount is guaranteed to be no greater than bufferSize.


flowOut :: a -> Ptr Word8 -> Int -> IO (a, Int)Source

exhausted :: a -> IO BoolSource


class Sink a whereSource

To a Sink, the requested amount of 'Word8'\'s flows from a Ptr. The requested amount is guaranteed to be no greater than bufferSize.


flowIn :: a -> Ptr Word8 -> Int -> IO aSource

bufferSize :: IntSource

The size of one chunk of data. A Ptr Word8 given to a Tap or Sink is guaranteed to have room for this many 'Word8'\'s, but no more.

pipe :: (Tap t, Sink s) => FilePath -> [(FilePath, [String])] -> t -> s -> IO (t, s)Source

Pipes data from the Tap to the Sink through all the commands named, in the given working directory.

Be careful! All IO is at the byte level: this means that piping even a String such as "foo" will result in the raw UTF-32 moving: the bytes (in my case; I believe this is implementation-dependent) in question are not the ASCII [102, 111, 111] but rather [102, 0, 0, 0, 111, 0, 0, 0, 111, 0, 0, 0].

Note to Windows users: since hGetBufNonBlocking doesn't work on Windows (it blocks despite its name, see http://hackage.haskell.org/trac/ghc/ticket/806), this pipeline uses a non-constant amount of space. The amount used is linear in the amount of data used at any point in the pipeline. So if you want to pipe 20 gibioctets of data to a program, you better make sure you have at least said amount of memory available. (In fact, ByteStrings are used, and their documentation suggests that you might want twice that, just in case.)

In addition, the Tap and Sink classes are meant for the POSIX code: having to move data through the Ptr Word8 types, bufferSize bytes at a time, results in extra complexity.

If you want to do something about the above, ideally fix the GHC ticket (probably nontrivial) and let me know so that I can activate the better code for Windows as well. Alternatively, feel free to code an implementation of this which works on Windows.

pipe' :: (Tap t, Sink s) => [(FilePath, [String])] -> t -> s -> IO (t, s)Source

A convenience function for when you don't care about the working directory.

 pipe' = pipe "."

pipeString :: [(FilePath, [String])] -> String -> IO StringSource

A convenience function for the common case of piping from a String to a String. This uses the word8ToString and stringToWord8 functions and thus loses information if your Chars are non-ASCII.

word8ToString :: [Word8] -> StringSource

A helper function which converts a [Word8] to a String by mapping chr over the octets.

In most cases, when you wish to pipe data to a String, you do not want to interpret the results as the raw byte pattern of Chars, so you use [Word8] as the Sink type. This function handles the common case of ASCII data simply—if you're dealing with non-ASCII data you probably need to handle the results in a different way.

stringToWord8 :: String -> [Word8]Source

The inverse of word8ToString. Any Chars greater than 255 are truncated: once again, be careful with non-ASCII.