diff --git a/Binary.hs b/Binary.hs
new file mode 100644
--- /dev/null
+++ b/Binary.hs
@@ -0,0 +1,203 @@
+-- On linux/x86, this module needs to be compiled with -fasm
+--
+-- (c) The University of Glasgow 2002
+--
+-- Binary I/O library, with special tweaks for GHC
+-- and
+-- Unboxed mutable Ints
+--
+-- Based on the nhc98 Binary library, which is copyright
+-- (c) Malcolm Wallace and Colin Runciman, University of York, 1998.
+-- Under the terms of the license for that software, we must tell you
+-- where you can obtain the original version of the Binary library, namely
+--     http://www.cs.york.ac.uk/fp/nhc98/
+
+module Binary ( Binary(..), openBinIO_ ) where
+
+#include "MachDeps.h"
+
+#ifndef SIZEOF_HSINT
+#define SIZEOF_HSINT  INT_SIZE_IN_BYTES
+#endif
+
+import Data.Char        (ord, chr)
+import Foreign          (Int32, Int64, Word8, Word32, Word64
+                        ,Bits(shiftR, shiftL, (.|.), (.&.)))
+import System.IO as IO  (Handle, hPutChar, hGetChar)
+
+import GHC.IOBase       (IO(..))
+import GHC.Exts
+
+import qualified Data.ByteString as P (hGet,hPut)
+import qualified Data.ByteString.Base as P (ByteString(..))
+
+------------------------------------------------------------------------
+
+data BinHandle = BinIO {-# UNPACK #-} !FastMutInt {-# UNPACK #-} !IO.Handle
+
+class Binary a where
+    put_   :: BinHandle -> a -> IO ()
+    get    :: BinHandle -> IO a
+
+openBinIO_ :: IO.Handle -> IO BinHandle
+openBinIO_ h = openBinIO h (error "Binary.BinHandle: no user data")
+
+openBinIO :: Handle -> t -> IO BinHandle
+openBinIO h _mod = do
+  r <- newFastMutInt
+  writeFastMutInt r 0
+  return (BinIO r h)
+
+-- -----------------------------------------------------------------------------
+-- Low-level reading/writing of bytes
+
+putWord8 :: BinHandle -> Word8 -> IO ()
+putWord8 (BinIO ix_r h) w = do
+    ix <- readFastMutInt ix_r
+    hPutChar h (chr (fromIntegral w))   -- XXX not really correct
+    writeFastMutInt ix_r (ix+1)
+    return ()
+
+getWord8 :: BinHandle -> IO Word8
+getWord8 (BinIO ix_r h) = do
+    ix <- readFastMutInt ix_r
+    c <- hGetChar h
+    writeFastMutInt ix_r (ix+1)
+    return $! (fromIntegral (ord c))    -- XXX not really correct
+
+putByte :: BinHandle -> Word8 -> IO ()
+putByte bh w = put_ bh w
+
+-- -----------------------------------------------------------------------------
+-- Primitve Word writes
+
+instance Binary Word8 where
+  put_ = putWord8
+  get  = getWord8
+
+instance Binary Word32 where
+  put_ h w = do
+    putByte h (fromIntegral (w `shiftR` 24))
+    putByte h (fromIntegral ((w `shiftR` 16) .&. 0xff))
+    putByte h (fromIntegral ((w `shiftR` 8)  .&. 0xff))
+    putByte h (fromIntegral (w .&. 0xff))
+  get h = do
+    w1 <- getWord8 h
+    w2 <- getWord8 h
+    w3 <- getWord8 h
+    w4 <- getWord8 h
+    return $! ((fromIntegral w1 `shiftL` 24) .|. 
+           (fromIntegral w2 `shiftL` 16) .|. 
+           (fromIntegral w3 `shiftL`  8) .|. 
+           (fromIntegral w4))
+
+instance Binary Word64 where
+  put_ h w = do
+    putByte h (fromIntegral (w `shiftR` 56))
+    putByte h (fromIntegral ((w `shiftR` 48) .&. 0xff))
+    putByte h (fromIntegral ((w `shiftR` 40) .&. 0xff))
+    putByte h (fromIntegral ((w `shiftR` 32) .&. 0xff))
+    putByte h (fromIntegral ((w `shiftR` 24) .&. 0xff))
+    putByte h (fromIntegral ((w `shiftR` 16) .&. 0xff))
+    putByte h (fromIntegral ((w `shiftR`  8) .&. 0xff))
+    putByte h (fromIntegral (w .&. 0xff))
+  get h = do
+    w1 <- getWord8 h
+    w2 <- getWord8 h
+    w3 <- getWord8 h
+    w4 <- getWord8 h
+    w5 <- getWord8 h
+    w6 <- getWord8 h
+    w7 <- getWord8 h
+    w8 <- getWord8 h
+    return $! ((fromIntegral w1 `shiftL` 56) .|. 
+           (fromIntegral w2 `shiftL` 48) .|. 
+           (fromIntegral w3 `shiftL` 40) .|. 
+           (fromIntegral w4 `shiftL` 32) .|. 
+           (fromIntegral w5 `shiftL` 24) .|. 
+           (fromIntegral w6 `shiftL` 16) .|. 
+           (fromIntegral w7 `shiftL`  8) .|. 
+           (fromIntegral w8))
+
+instance Binary Int32 where
+  put_ h w = put_ h (fromIntegral w :: Word32)
+  get h    = do w <- get h; return $! (fromIntegral (w::Word32))
+
+instance Binary Int64 where
+  put_ h w = put_ h (fromIntegral w :: Word64)
+  get h    = do w <- get h; return $! (fromIntegral (w::Word64))
+
+-- -----------------------------------------------------------------------------
+-- Instances for standard types
+
+instance Binary Int where
+#if SIZEOF_HSINT == 4
+    put_ bh i = put_ bh (fromIntegral i :: Int32)
+    get  bh = do
+    x <- get bh
+    return $! (fromIntegral (x :: Int32))
+#elif SIZEOF_HSINT == 8
+    put_ bh i = put_ bh (fromIntegral i :: Int64)
+    get  bh = do
+    x <- get bh
+    return $! (fromIntegral (x :: Int64))
+#else
+#error "unsupported sizeof(HsInt)"
+#endif
+--    getF bh   = getBitsF bh 32
+
+instance (Binary a, Binary b) => Binary (a,b) where
+    put_ bh (a,b) = do put_ bh a; put_ bh b
+    get bh        = do a <- get bh
+                       b <- get bh
+                       return (a,b)
+
+-- Instances for ByteStrings
+instance Binary P.ByteString where
+    put_ bh@(BinIO ix_r h) ps@(P.PS _ptr _s l) = do
+            put_ bh l   -- size
+            ix <- readFastMutInt ix_r
+            P.hPut h ps
+            writeFastMutInt ix_r (ix+l)
+            return ()
+
+    get bh@(BinIO ix_r h) = do
+            l  <- get bh
+            ix <- readFastMutInt ix_r
+            ps <- {-#SCC "Binary.ByteString.get" #-}P.hGet h l
+            writeFastMutInt ix_r (ix+l)
+            return $! ps
+
+{-
+            ps <- P.generate l $ \ptr -> do
+                  let loop p n# | n# ==# l# = return ()
+                                | otherwise = do
+                                        c <- hGetChar h
+                                        poke p (c2w c)
+                                        loop (p `plusPtr` 1) (n# +# 1#)
+                  loop ptr 0#
+                  return l
+            where
+                c2w = fromIntegral . ord
+-}
+
+------------------------------------------------------------------------
+-- FastMutInt
+--
+data FastMutInt = FastMutInt !(MutableByteArray# RealWorld)
+
+newFastMutInt :: IO FastMutInt
+newFastMutInt = IO $ \s ->
+  case newByteArray# size s of { (# s', arr #) ->
+  (# s', FastMutInt arr #) }
+  where I# size = SIZEOF_HSINT
+
+readFastMutInt :: FastMutInt -> IO Int
+readFastMutInt (FastMutInt arr) = IO $ \s ->
+  case readIntArray# arr 0# s of { (# s', i #) ->
+  (# s', I# i #) }
+
+writeFastMutInt :: FastMutInt -> Int -> IO ()
+writeFastMutInt (FastMutInt arr) (I# i) = IO $ \s ->
+  case writeIntArray# arr 0# i s of { s' ->
+  (# s', () #) }
diff --git a/Config.hs b/Config.hs
new file mode 100644
--- /dev/null
+++ b/Config.hs
@@ -0,0 +1,86 @@
+-- 
+-- Copyright (c) 2005 Don Stewart - http://www.cse.unsw.edu.au/~dons
+-- 
+-- This program is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation; either version 2 of
+-- the License, or (at your option) any later version.
+-- 
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- General Public License for more details.
+-- 
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+-- 
+module Config where
+
+import Style
+
+#include "config.h"
+
+defaultStyle :: UIStyle
+defaultStyle  = UIStyle { window     = Style defaultfg    defaultbg
+                        , titlebar   = Style brightwhite  green
+                        , selected   = Style blue         defaultbg
+                        , cursors    = Style black        cyan
+                        , combined   = Style brightwhite  cyan
+                        , warnings   = Style red          defaultbg
+                        , helpscreen = Style black        white 
+                        , blockcursor= Style black        red
+                        , progress   = Style cyan         white }
+
+-- | A style more suitable for light backgrounds (used if HMP_HAS_LIGHT_BG=true)
+lightBgStyle :: UIStyle
+lightBgStyle = 
+           defaultStyle { selected   = Style darkblue     defaultbg
+                        , warnings   = Style darkred      defaultbg }
+
+--
+-- | Another style for dark backgrounds, reminiscent of mutt
+--
+muttStyle :: UIStyle
+muttStyle   = UIStyle { window     = Style brightwhite  black
+                      , titlebar   = Style green        blue
+                      , selected   = Style brightwhite  black
+                      , cursors    = Style black        cyan
+                      , combined   = Style black        cyan
+                      , warnings   = Style brightwhite  red
+                      , helpscreen = Style black        cyan
+                      , blockcursor= Style black        darkred
+                      , progress   = Style cyan         white  }
+
+bwStyle :: UIStyle 
+bwStyle = UIStyle {
+        window      = Style defaultfg   defaultbg
+       ,titlebar    = Style reversefg   reversebg
+       ,selected    = Style brightwhite defaultbg
+       ,cursors     = Style reversefg   reversebg
+       ,combined    = Style reversefg   reversebg
+       ,warnings    = Style reversefg   reversebg
+       ,helpscreen  = Style reversefg   reversebg
+       ,blockcursor = Style reversefg   reversebg
+       ,progress    = Style reversefg   reversebg
+    }
+           
+------------------------------------------------------------------------
+
+package :: String
+package = "hmp3"
+
+versinfo :: String
+versinfo  = package++" "++ version
+    where 
+      version :: String
+      version = "1.1" ++ if (not . null) (PATCH_COUNT :: String) && (PATCH_COUNT /= "1")
+                         then "p" ++ PATCH_COUNT
+                         else ""
+
+help :: String
+help = "- curses-based MP3 player"
+
+darcsinfo :: String
+darcsinfo = "darcs get --partial http://www.cse.unsw.edu.au/~dons/code/hmp3"
diff --git a/Core.hs b/Core.hs
new file mode 100644
--- /dev/null
+++ b/Core.hs
@@ -0,0 +1,570 @@
+-- 
+-- Copyright (c) 2005 Don Stewart - http://www.cse.unsw.edu.au/~dons
+-- 
+-- This program is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation; either version 2 of
+-- the License, or (at your option) any later version.
+-- 
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- General Public License for more details.
+-- 
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+-- 
+
+--
+-- | Main module. 
+--
+module Core (
+        start,
+        shutdown,
+        seekLeft, seekRight, up, down, pause, nextMode, playNext, playPrev,
+        quit, putmsg, clrmsg, toggleHelp, play, jumpToPlaying, jump, {-, add-}
+        writeSt, readSt,
+        jumpToMatch, jumpToMatchFile,
+        toggleFocus, jumpToNextDir, jumpToPrevDir,
+        loadConfig,
+    ) where
+
+import Prelude hiding (catch)
+
+import Syntax
+import Lexer                (parser)
+import State
+import Style
+import Utils
+import FastIO               (send,fdToCFile,forceNextPacket)
+import Tree hiding (File,Dir)
+import qualified Tree (File,Dir)
+import Regex
+import qualified UI
+
+import {-# SOURCE #-} Keymap (keymap)
+
+import qualified Data.ByteString.Char8 as P (pack,empty,ByteString,joinWithChar)
+import Data.ByteString (useAsCString)
+
+import Data.Array               ((!), bounds, Array)
+import Data.Maybe               (isJust,fromJust)
+import Control.Monad            (liftM, when)
+import System.Directory         (doesFileExist,findExecutable)
+import System.Environment       (getEnv)
+import System.Exit              (ExitCode(ExitSuccess),exitWith)
+import System.IO                (hPutStrLn, hGetLine, stderr, hFlush)
+import System.IO.Unsafe         (unsafeInterleaveIO)
+import System.Process           (waitForProcess)
+import System.Random            (getStdRandom, randomR)
+import System.Time              (getClockTime)
+
+import System.Posix.Process     (exitImmediately)
+import System.Posix.User        (getUserEntryForID, getRealUserID, homeDirectory)
+
+import Control.Concurrent
+import Control.Exception
+
+import GHC.Handle               (fdToHandle)
+
+#include "config.h"
+
+------------------------------------------------------------------------
+
+start :: Either SerialT [P.ByteString] -> IO ()
+start ms = Control.Exception.handle (\e -> shutdown (Just (show e))) $ do
+
+    t0 <- forkIO mpgLoop    -- start this off early, to give mpg321 a time to settle
+
+    c <- UI.start -- initialise curses
+
+    (ds,fs,i,m)   -- construct the state
+        <- case ms of
+           Right roots -> do (a,b) <- buildTree roots 
+                             return (a,b,0,Normal)
+
+           Left st     -> return (ser_darr st
+                                 ,ser_farr st
+                                 ,ser_indx st
+                                 ,ser_mode st)
+
+    now   <- getClockTime
+
+    -- fork some threads
+    t1 <- forkIO mpgInput
+    t2 <- forkIO refreshLoop
+    t3 <- forkIO clockLoop
+    t4 <- forkIO uptimeLoop
+    t5 <- forkIO errorLoop
+
+    silentlyModifyST $ \s -> s 
+        { music        = fs
+        , folders      = ds
+        , size         = 1 + (snd . bounds $ fs)
+        , cursor       = i
+        , current      = i
+        , mode         = m
+        , uptime       = drawUptime now now
+        , boottime     = now 
+        , config       = c
+        , threads      = [t0,t1,t2,t3,t4,t5] }
+
+    loadConfig
+
+    when (0 <= (snd . bounds $ fs)) play -- start the first song
+
+    run         -- won't restart if this fails!
+
+------------------------------------------------------------------------
+
+-- | Uniform loop and thread handler (subtle, and requires exitImmediately)
+forever :: IO () -> IO ()
+forever fn = catch (repeatM_ fn) handler
+    where
+        handler :: Exception -> IO ()
+        handler e =
+            when (not.exitTime $ e) $
+                (warnA . show) e >> (forever fn)        -- reopen the catch
+
+-- | Generic handler
+-- For profiling, make sure to return True for anything:
+exitTime :: Exception -> Bool
+exitTime e | isJust . ioErrors $ e   = False -- ignore
+           | isJust . errorCalls $ e = False -- ignore
+           | isJust . userErrors $ e = False -- ignore
+           | otherwise               = True
+-- exitTime _ = True
+
+------------------------------------------------------------------------
+
+-- | Process loop, launch mpg321, set the handles in the state
+-- and then wait for the process to die. If it does, restart it.
+--
+-- If we're unable to start at all, we should say something sensible
+-- For example, if we can't start it two times in a row, perhaps give up?
+--
+mpgLoop :: IO ()
+mpgLoop = forever $ do
+    mmpg <- findExecutable (MPG321 :: String)
+    case mmpg of
+      Nothing     -> quit (Just $ "Cannot find " ++ MPG321 ++ " in path")
+      Just mpg321 -> do 
+
+        -- if we're never able to start mpg321, do something sensible
+        mv <- catch (popen (mpg321 :: String) ["-R","-"] >>= return . Just)
+                    (\e -> do warnA ("Unable to start " ++ MPG321 ++ ": " ++ show e)
+                              return Nothing)
+        case mv of
+            Nothing -> threadDelay (1000 * 500) >> mpgLoop
+            Just (r,w,e,pid) -> do
+
+            hw          <- fdToHandle (fdToInt w)  -- so we can use Haskell IO
+            ew          <- fdToHandle (fdToInt e)  -- so we can use Haskell IO
+            filep       <- fdToCFile r                   -- so we can use C IO
+            mhw         <- newMVar hw
+            mew         <- newMVar ew
+            mfilep      <- newMVar filep
+
+            modifyST $ \st ->
+                       st { mp3pid    = Just pid
+                          , writeh    = mhw
+                          , errh      = mew
+                          , readf     = mfilep 
+                          , status    = Stopped
+                          , info      = Nothing
+                          , id3       = Nothing }
+          
+            catch (waitForProcess (pid2phdl pid)) (\_ -> return ExitSuccess)
+            stop <- getsST doNotResuscitate
+            when (stop) $ exitWith ExitSuccess
+            warnA $ "Restarting " ++ mpg321 ++ " ..."
+
+------------------------------------------------------------------------
+
+-- | When the editor state has been modified, refresh, then wait
+-- for it to be modified again.
+refreshLoop :: IO ()
+refreshLoop = getsST modified >>= \mvar -> forever $ takeMVar mvar >> UI.refresh
+
+------------------------------------------------------------------------
+
+-- | Once a minute read the clock time
+uptimeLoop :: IO ()
+uptimeLoop = forever $ do
+    threadDelay delay 
+    now <- getClockTime 
+    modifyST $ \st -> st { uptime = drawUptime (boottime st) now }
+  where
+    delay = 60 * 1000 * 1000 -- 1 minute
+
+------------------------------------------------------------------------
+
+-- | Once each half second, wake up a and redraw the clock
+clockLoop :: IO ()
+clockLoop = forever $ threadDelay delay >> UI.refreshClock
+  where
+    delay = 500 * 1000 -- 0.5 second
+
+------------------------------------------------------------------------
+
+-- | Handle, and display errors produced by mpg321
+errorLoop :: IO ()
+errorLoop = forever $ do
+    s <- getsST errh >>= readMVar >>= hGetLine
+    if s == "No default libao driver available."
+        then quit $ Just $ s ++ " Perhaps another instance of hmp3 is running?"
+        else warnA s
+
+------------------------------------------------------------------------
+
+-- | Handle messages arriving over a pipe from the decoder process. When
+-- shutdown kills the other end of the pipe, hGetLine will fail, so we
+-- take that chance to exit.
+--
+mpgInput :: IO ()
+mpgInput = forever $ do
+    mvar <- getsST readf
+    fp   <- readMVar mvar
+    res  <- parser fp
+    case res of
+        Right m -> handleMsg m
+        Left e  -> (warnA.show) e  -- error from pipe
+
+------------------------------------------------------------------------
+
+-- | The main thread: handle keystrokes fed to us by curses
+run :: IO ()
+run = forever $ sequence_ . keymap =<< getKeys
+  where
+    getKeys = unsafeInterleaveIO $ do
+            c  <- UI.getKey
+            cs <- getKeys
+            return (c:cs) -- A lazy list of curses keys
+
+------------------------------------------------------------------------
+
+-- | Close most things. Important to do all the jobs:
+shutdown :: Maybe String -> IO ()
+shutdown ms = 
+    (do silentlyModifyST $ \st -> st { doNotResuscitate = True }
+        catch writeSt (\_ -> return ())
+        withST $ \st -> do
+            case mp3pid st of
+                Nothing  -> return ()
+                Just pid -> do
+                    h <- readMVar (writeh st)
+                    send h Quit                        -- ask politely
+                    waitForProcess $ pid2phdl pid
+                    return ())
+
+    `finally` 
+
+    (do isXterm <- getsST xterm
+        UI.end isXterm
+        when (isJust ms) $ hPutStrLn stderr (fromJust ms) >> hFlush stderr
+        exitImmediately ExitSuccess)    -- race. a thread might touch the screen
+--      return ())
+
+------------------------------------------------------------------------
+-- 
+-- Write incoming messages from the encoder to the global state in the
+-- right pigeon hole.
+--
+handleMsg :: Msg -> IO ()
+handleMsg (T _)                = return ()
+handleMsg (I i)                = modifyST $ \s -> s { info = Just i }
+handleMsg (F (File (Left  _))) = modifyST $ \s -> s { id3 = Nothing }
+handleMsg (F (File (Right i))) = modifyST $ \s -> s { id3 = Just i  }
+
+handleMsg (S t) = do
+    modifyST $ \s -> s { status  = t }
+    when (t == Stopped) $ do   -- transition to next song
+        playNext
+-- vincenz: Redundant, this is checked in playNext
+--        r <- getsST mode
+--        if r == Random then playRandom else playNext
+
+handleMsg (R f) = do
+    silentlyModifyST $ \st -> st { clock = Just f }
+    getsST clockUpdate >>= flip when UI.refreshClock
+
+------------------------------------------------------------------------
+--
+-- Basic operations
+--
+
+-- | Seek backward in song
+seekLeft :: IO ()
+seekLeft = seek $ \g -> max 0 (currentFrame g - 400)
+
+-- | Seek forward in song
+seekRight :: IO ()
+seekRight = seek $ \g -> currentFrame g + (min 400 (framesLeft g))
+
+-- | Generic seek
+seek :: (Frame -> Int) -> IO ()
+seek fn = do
+    f <- getsST clock
+    case f of 
+        Nothing -> return ()
+        Just g  -> do
+            withST $ \st -> do
+                h <- readMVar (writeh st)
+                send h $ Jump (fn g)
+                forceNextPacket         -- don't drop the next Frame.
+            silentlyModifyST $ \st -> st { clockUpdate = True }
+
+------------------------------------------------------------------------
+
+-- | Move cursor up or down
+up, down :: IO ()
+up   = modifySTM $ flip jumpTo (subtract 1)
+down = modifySTM $ flip jumpTo (+1)
+
+-- | Move cursor to specified index
+jump :: Int -> IO ()
+jump i = modifySTM $ flip jumpTo (const i)
+
+-- | Generic jump
+jumpTo :: HState -> (Int -> Int) -> IO HState
+jumpTo st fn = do
+    let l = max 0 (size st - 1)
+        i = fn (cursor st)
+        n = if i > l then l else if i < 0 then 0 else i
+    return st { cursor = n }
+
+------------------------------------------------------------------------
+
+-- | Load and play the song under the cursor
+play :: IO ()
+play = modifySTM $ \st -> playAtN st (const $ cursor st)
+
+-- | Play a random song
+playRandom :: IO ()
+playRandom = modifySTM $ \st -> do
+    n <- getStdRandom (randomR (0, max 0 (size st -1)))
+    playAtN st (const n)
+
+-- | Play the song before the current song, if we're not at the beginning
+-- If we're at the beginning, and loop mode is on, then loop to the end
+-- If we're in random mode, play the next random track
+playPrev :: IO ()
+playPrev = do
+    md <- getsST mode
+    if md == Random then playRandom else
+      modifySTM $ \st -> do
+      let i   = current st
+      case () of {_
+        | i > 0             -> playAtN st (subtract 1)      -- just the prev track
+        | mode st == Loop   -> playAtN st (const (size st - 1))  -- maybe loop
+        | otherwise         -> return  st            -- else stop at end
+      }
+
+-- | Play the song following the current song, if we're not at the end
+-- If we're at the end, and loop mode is on, then loop to the start
+-- If we're in random mode, play the next random track
+playNext :: IO ()
+playNext = do
+    md <- getsST mode
+    if md == Random then playRandom else
+      modifySTM $ \st -> do
+      let i   = current st
+      case () of {_
+        | i < size st - 1   -> playAtN st (+ 1)      -- just the next track
+        | mode st == Loop   -> playAtN st (const 0)  -- maybe loop
+        | otherwise         -> return  st            -- else stop at end
+      }
+
+-- | Generic next song selection
+-- If the cursor and current are currently the same, continue that.
+playAtN :: HState -> (Int -> Int) -> IO HState
+playAtN st fn = do
+    let m   = music st
+        i   = current st
+        fe  = m ! (fn i)
+        f   = P.joinWithChar '/' (dname $ folders st ! fdir fe) (fbase fe)
+        j   = cursor  st
+        st' = st { current = fn i
+                 , status  = Playing
+                 , cursor  = if i == cursor st then fn i else j }
+    h <- readMVar (writeh st)
+    send h (Load f)
+    return st'
+
+------------------------------------------------------------------------
+
+-- | Toggle pause on the current song
+pause :: IO ()
+pause = withST $ \st -> readMVar (writeh st) >>= flip send Pause
+
+-- | Shutdown and exit
+quit :: Maybe String -> IO ()
+quit = shutdown
+
+------------------------------------------------------------------------
+
+-- | Move cursor to currently playing song
+jumpToPlaying :: IO ()
+jumpToPlaying = modifyST $ \st -> st { cursor = (current st) }
+
+-- | Move cursor to first song in next directory (or wrap)
+jumpToNextDir, jumpToPrevDir :: IO ()
+jumpToNextDir = jumpToDir (\i len -> min (i+1) (len-1))
+jumpToPrevDir = jumpToDir (\i _   -> max (i-1) 0)
+
+-- | Generic jump to dir
+jumpToDir :: (Int -> Int -> Int) -> IO ()
+jumpToDir fn = modifyST $ \st -> if size st == 0 then st else
+    let i   = fdir (music st ! cursor st)
+        len = 1 + (snd . bounds $ folders st)
+        d   = fn i len
+    in st { cursor = dlo ((folders st) ! d) }
+
+------------------------------------------------------------------------
+
+--
+-- a bit of bounded parametric polymorphism so we can abstract over record selectors
+-- in the regex search stuff below
+--
+class Lookup a       where extract :: a -> FilePathP
+instance Lookup Tree.Dir  where extract = dname
+instance Lookup Tree.File where extract = fbase
+
+jumpToMatchFile :: Maybe (String,Bool) -> IO ()
+jumpToMatchFile re = genericJumpToMatch re k sel
+    where k = \st -> (music st, if size st == 0 then -1 else cursor st, size st)
+          sel i _ = i
+
+jumpToMatch  :: Maybe (String,Bool) -> IO ()
+jumpToMatch     re = genericJumpToMatch re k sel
+    where k = \st -> (folders st
+                     ,if size st == 0 then -1 else fdir (music st ! cursor st)
+                     ,1 + (snd . bounds $ folders st))
+          sel i st = dlo (folders st ! i)
+
+genericJumpToMatch :: Lookup a
+                   => Maybe (String,Bool)
+                   -> (HState -> (Array Int a, Int, Int))
+                   -> (Int -> HState -> Int)
+                   -> IO ()
+
+genericJumpToMatch re k sel = do
+    found <- modifySTM_ $ \st -> do
+        mre <- case re of   -- work out if we have no pattern, a cached pattern, or a new pattern
+                Nothing -> case regex st of
+                                Nothing     -> return Nothing
+                                Just (r,d)  -> return $ Just (r,d)
+                Just (s,d)  -> do v <- regcomp s (regExtended + regIgnoreCase + regNewline)
+                                  return $ Just (v,d)
+        case mre of
+            Nothing -> return (st,False)    -- no pattern
+            Just (p,forwards) -> do
+
+            let (fs,cur,m) = k st
+
+                loop fn inc n
+                    | fn n      = return Nothing
+                    | otherwise = useAsCString (extract (fs ! n)) $ \s -> do
+                        v <- regexec p s 0
+                        case v of
+                            Nothing -> loop fn inc $! inc n
+                            Just _  -> return $ Just n
+
+            mi <- if forwards then loop (>=m) (+1)         (cur+1)
+                              else loop (<0)  (subtract 1) (cur-1)
+
+            let st' = st { regex = Just (p,forwards) }
+            return $ case mi of
+                Nothing -> (st',False)
+                Just i  -> (st' { cursor = sel i st }, True)
+
+    when (not found) $ putmsg (Fast (P.pack "No match found.") defaultSty) >> touchST
+
+------------------------------------------------------------------------
+
+-- | Show\/hide the help window
+toggleHelp :: IO ()
+toggleHelp = modifyST $ \st -> st { helpVisible = not (helpVisible st) }
+
+-- | Focus the minibuffer
+toggleFocus :: IO ()
+toggleFocus = modifyST $ \st -> st { miniFocused = not (miniFocused st) }
+
+-- | Toggle the mode flag
+nextMode :: IO ()
+nextMode = modifyST $ \st -> st { mode = next (mode st) }
+    where
+        next v = if v == maxBound then minBound else succ v
+
+------------------------------------------------------------------------
+
+-- | Saving the playlist 
+-- Only save if there's something to save. Should preven dbs being wiped
+-- if curses crashes before the state is read.
+writeSt :: IO ()
+writeSt = do
+    home <- getHome
+    let f = home </> ".hmp3db"
+    withST $ \st -> do
+        let arr1 = music st
+            arr2 = folders st
+            idx  = current st
+            mde  = mode st
+        when (size st > 0) $ writeTree f $ SerialT {
+                                            ser_farr = arr1
+                                           ,ser_darr = arr2
+                                           ,ser_indx = idx
+                                           ,ser_mode = mde
+                                          }
+
+-- | Read the playlist back
+readSt :: IO (Maybe SerialT)
+readSt = do
+    home <- getHome
+    let f = home </> ".hmp3db"
+    b <- doesFileExist f
+    if b then liftM Just $! readTree f else return Nothing
+
+-- | Find a user's home in a canonical sort of way
+getHome :: IO String
+getHome = Control.Exception.catch 
+    (getRealUserID >>= getUserEntryForID >>= (return . homeDirectory))
+    (\_ -> getEnv "HOME")
+
+------------------------------------------------------------------------
+-- Read styles from ~/.hmp3
+--
+loadConfig :: IO ()   
+loadConfig = do
+    home <- getHome
+    let f = home </> ".hmp3"
+    b <- doesFileExist f
+    when b $ do     -- otherwise used compiled-in values
+        str  <- readFile f
+        msty <- catch (readM str >>= return . Just) 
+                      (const $ warnA "Parse error in ~/.hmp3" >> return Nothing)
+        case msty of
+            Nothing  -> return ()
+            Just rsty -> do
+                let sty = buildStyle rsty
+                initcolours sty
+                modifyST $ \st -> st { config = sty }
+    UI.resetui
+
+------------------------------------------------------------------------
+-- Editing the minibuffer
+
+putmsg :: StringA -> IO ()
+putmsg s = silentlyModifyST $ \st -> st { minibuffer = s }
+
+-- | Modify without triggering a refresh
+clrmsg :: IO ()
+clrmsg = putmsg (Fast P.empty defaultSty)
+
+--
+warnA :: String -> IO ()
+warnA x = do 
+    sty <- getsST config
+    putmsg $ Fast (P.pack x) (warnings sty)
diff --git a/Curses.hsc b/Curses.hsc
new file mode 100644
--- /dev/null
+++ b/Curses.hsc
@@ -0,0 +1,638 @@
+--
+-- Copyright (c) 2002-2004 John Meacham (john at repetae dot net)
+-- Copyright (c) 2004-2005 Don Stewart - http://www.cse.unsw.edu.au/~dons
+-- 
+-- Permission is hereby granted, free of charge, to any person obtaining a
+-- copy of this software and associated documentation files (the
+-- "Software"), to deal in the Software without restriction, including
+-- without limitation the rights to use, copy, modify, merge, publish,
+-- distribute, sublicense, and/or sell copies of the Software, and to
+-- permit persons to whom the Software is furnished to do so, subject to
+-- the following conditions:
+-- 
+-- The above copyright notice and this permission notice shall be included
+-- in all copies or substantial portions of the Software.
+-- 
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+-- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+-- 
+
+--
+-- | Binding to the [wn]curses library. From the ncurses man page:
+--
+-- >      The curses library routines give the user a terminal-inde-
+-- >      pendent method of updating character screens with  reason-
+-- >      able  optimization.
+-- 
+-- Sections of the quoted documentation are from the OpenBSD man pages,
+-- which are distributed under a BSD license.
+--
+-- A useful reference is: 
+--        /Writing Programs with NCURSES/, by Eric S. Raymond and Zeyd
+--        M. Ben-Halim, <http://dickey.his.com/ncurses/>
+--
+-- attrs dont work with Irix curses.h. This should be fixed.
+--
+
+#include "utils.h"
+
+module Curses (
+
+    initCurses,     -- :: IO () -> IO ()
+    resetParams,    -- :: IO ()
+
+    stdScr,         -- :: Window
+    endWin,         -- :: IO ()
+
+    keypad,         -- :: Window -> Bool -> IO ()
+    scrSize,        -- :: IO (Int, Int)
+    refresh,        -- :: IO ()
+    getCh,          -- :: IO Char
+
+    -- * Line drawing
+    waddnstr,       -- :: Window -> CString -> CInt -> IO CInt
+    bkgrndSet,      -- :: Attr -> Pair -> IO ()
+    clrToEol,       -- :: IO ()
+    wMove,          -- :: Window -> Int -> Int -> IO ()
+
+    -- * Key codes
+    keyBackspace, keyUp, keyDown, keyNPage, keyHome, keyPPage, keyEnd,
+    keyLeft, keyRight,
+#ifdef KEY_RESIZE
+    keyResize,
+#endif
+
+    -- * Cursor
+    CursorVisibility(..),
+    cursSet,        -- :: CInt -> IO CInt
+    getYX,          -- :: Window -> IO (Int, Int)
+
+    -- * Colours
+    Pair(..), Color,
+    initPair,           -- :: Pair -> Color -> Color -> IO ()
+    color,              -- :: String -> Maybe Color
+    hasColors,          -- :: IO Bool
+
+    -- * Attributes
+    Attr,
+    attr0, setBold, setReverse,
+    attrSet,
+    attrPlus,           -- :: Attr -> Attr -> Attr
+
+    -- * error handling
+    throwIfErr_,    -- :: Num a => String -> IO a -> IO ()
+    
+  ) where 
+
+#if HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+
+import qualified Data.ByteString.Char8 as P
+
+import Prelude hiding       (pi)
+import Data.Char            (ord, chr)
+
+import Control.Monad        (liftM, when)
+import Control.Concurrent   (yield, threadWaitRead)
+
+import Foreign.C.Types      (CInt, CShort)
+import Foreign.C.String     (CString)
+import Foreign
+
+#ifdef SIGWINCH
+import System.Posix.Signals (installHandler, Signal, Handler(Catch))
+#endif
+
+--
+-- If we have the SIGWINCH signal, we use that, with a custom handler,
+-- to determine when to resize the screen. Otherwise, we use a similar
+-- handler that looks for KEY_RESIZE in the input stream -- the result
+-- is a less responsive update, however.
+--
+
+------------------------------------------------------------------------
+--
+-- | Start it all up
+--
+initCurses :: IO () -> IO ()
+initCurses fn = do
+    initScr
+    b <- hasColors
+    when b $ startColor >> useDefaultColors
+    resetParams
+#ifdef SIGWINCH
+    -- does this still work?
+    installHandler cursesSigWinch (Catch fn) Nothing >> return ()
+#endif
+
+-- | A bunch of settings we need
+--
+resetParams :: IO ()
+resetParams = do
+    cBreak True
+    echo False          -- don't echo to the screen
+    nl True             -- always translate enter to \n
+    leaveOk True        -- not ok to leave cursor wherever it is
+    meta stdScr True    -- ask for 8 bit chars, so we can get Meta
+    keypad stdScr True  -- enable the keypad, so things like ^L (refresh) work
+    noDelay stdScr False  -- blocking getCh, no #ERR
+    return ()
+
+-- not needed, if keypad is True:
+--  defineKey (#const KEY_UP) "\x1b[1;2A"
+--  defineKey (#const KEY_DOWN) "\x1b[1;2B"
+--  defineKey (#const KEY_SLEFT) "\x1b[1;2D"
+--  defineKey (#const KEY_SRIGHT) "\x1b[1;2C"
+
+------------------------------------------------------------------------
+
+fi :: (Integral a, Num b) => a -> b
+fi = fromIntegral
+{-# INLINE fi #-}
+
+------------------------------------------------------------------------
+-- 
+-- Error handling, packed to save on all those strings
+--
+
+-- | Like throwIf, but for packed error messages
+throwPackedIf :: (a -> Bool) -> P.ByteString -> (IO a) -> (IO a)
+throwPackedIf p msg action = do
+    v <- action
+    if p v then (fail . P.unpack $ msg) else return v
+{-# INLINE throwPackedIf #-}
+
+-- | Arbitrary test 
+throwIfErr :: Num a => P.ByteString -> IO a -> IO a
+throwIfErr = throwPackedIf (== (#const ERR))
+{-# INLINE throwIfErr #-}
+
+-- | Discard result
+throwIfErr_ :: Num a => P.ByteString -> IO a -> IO ()
+throwIfErr_ a b = void $ throwIfErr a b
+{-# INLINE throwIfErr_ #-}
+
+-- | packed throwIfNull
+throwPackedIfNull :: P.ByteString -> IO (Ptr a) -> IO (Ptr a)
+throwPackedIfNull = throwPackedIf (== nullPtr)
+{-# INLINE throwPackedIfNull #-}
+
+------------------------------------------------------------------------
+
+type WindowTag = ()
+type Window = Ptr WindowTag
+
+--
+-- | The standard screen
+--
+stdScr :: Window
+stdScr = unsafePerformIO (peek stdscr)
+
+foreign import ccall "static &stdscr" 
+    stdscr :: Ptr Window
+
+--
+-- | initscr is normally the first curses routine to call when
+-- initializing a program. curs_initscr(3):
+--
+-- > To initialize the routines, the routine initscr or newterm
+-- > must be called before any of the other routines that  deal
+-- > with  windows  and  screens  are used. 
+--
+-- > The initscr code determines the terminal type and initial-
+-- > izes all curses data structures.  initscr also causes  the
+-- > first  call  to  refresh  to  clear the screen.  If errors
+-- > occur, initscr writes  an  appropriate  error  message  to
+-- > standard error and exits; otherwise, a pointer is returned
+-- > to stdscr.
+--
+initScr :: IO Window
+initScr = throwPackedIfNull (P.packAddress "initscr"##) c_initscr
+
+foreign import ccall unsafe "initscr" 
+    c_initscr :: IO Window
+
+--
+-- |> The cbreak routine
+-- > disables line buffering and erase/kill  character-process-
+-- > ing  (interrupt  and  flow  control  characters  are unaf-
+-- > fected), making characters typed by the  user  immediately
+-- > available  to  the  program.  The nocbreak routine returns
+-- > the terminal to normal (cooked) mode.
+--
+cBreak :: Bool -> IO ()
+cBreak True  = throwIfErr_ (P.packAddress "cbreak"##)   cbreak
+cBreak False = throwIfErr_ (P.packAddress "nocbreak"##) nocbreak
+
+foreign import ccall unsafe "cbreak"     cbreak :: IO CInt
+foreign import ccall unsafe "nocbreak" nocbreak :: IO CInt
+
+--
+-- |> The  echo  and  noecho routines control whether characters
+-- > typed by the user are echoed by getch as they  are  typed.
+-- > Echoing  by  the  tty  driver is always disabled, but ini-
+-- > tially getch is in echo  mode,  so  characters  typed  are
+-- > echoed.  Authors of most interactive programs prefer to do
+-- > their own echoing in a controlled area of the  screen,  or
+-- > not  to  echo  at  all, so they disable echoing by calling
+-- > noecho.  [See curs_getch(3) for a discussion of how  these
+-- > routines interact with cbreak and nocbreak.]
+--
+echo :: Bool -> IO ()
+echo False = throwIfErr_ (P.packAddress "noecho"##) noecho
+echo True  = throwIfErr_ (P.packAddress "echo"##)   echo_c
+
+foreign import ccall unsafe "noecho" noecho :: IO CInt
+foreign import ccall unsafe "echo"   echo_c :: IO CInt
+
+--
+-- |> The  nl  and  nonl routines control whether the underlying
+-- > display device translates the return key into  newline  on
+-- > input,  and  whether it translates newline into return and
+-- > line-feed on output (in either case, the call  addch('\n')
+-- > does the equivalent of return and line feed on the virtual
+-- > screen).  Initially, these translations do occur.  If  you
+-- > disable  them using nonl, curses will be able to make bet-
+-- > ter use of the line-feed capability, resulting  in  faster
+-- > cursor  motion.   Also, curses will then be able to detect
+-- > the return key.
+-- > 
+nl :: Bool -> IO ()
+nl True  = throwIfErr_ (P.packAddress "nl"##) nl_c
+nl False = throwIfErr_ (P.packAddress "nonl"##) nonl
+
+foreign import ccall unsafe "nl" nl_c :: IO CInt
+foreign import ccall unsafe "nonl" nonl :: IO CInt
+
+--
+-- | Enable the keypad of the user's terminal.
+--
+keypad :: Window -> Bool -> IO ()
+keypad win bf = throwIfErr_ (P.packAddress "keypad"##) $ 
+    keypad_c win (if bf then 1 else 0)
+
+foreign import ccall unsafe "keypad" 
+    keypad_c :: Window -> (#type bool) -> IO CInt
+
+-- |> The nodelay option causes getch to be a non-blocking call.
+-- > If  no input is ready, getch returns ERR.  If disabled (bf
+-- > is FALSE), getch waits until a key is pressed.
+--
+noDelay :: Window -> Bool -> IO ()
+noDelay win bf = throwIfErr_ (P.packAddress "nodelay"##) $ 
+    nodelay win (if bf then 1 else 0)
+
+foreign import ccall unsafe nodelay 
+    :: Window -> (#type bool) -> IO CInt
+
+--
+-- |> Normally, the hardware cursor is left at the  location  of
+-- > the  window  cursor  being  refreshed.  The leaveok option
+-- > allows the cursor to be left wherever the  update  happens
+-- > to leave it.  It is useful for applications where the cur-
+-- > sor is not used, since it  reduces  the  need  for  cursor
+-- > motions.   If  possible, the cursor is made invisible when
+-- > this option is enabled.
+--
+leaveOk  :: Bool -> IO CInt
+leaveOk bf = leaveok_c stdScr (if bf then 1 else 0)
+
+foreign import ccall unsafe "leaveok" 
+    leaveok_c :: Window -> (#type bool) -> IO CInt
+
+------------------------------------------------------------------------
+
+-- | The use_default_colors() and assume_default_colors() func-
+--   tions are extensions to the curses library.  They are used
+--   with terminals that support ISO 6429 color, or equivalent.
+--
+--  use_default_colors() tells the  curses library  to  assign terminal
+--  default foreground/background colors to color number  -1.
+--
+#if defined(HAVE_USE_DEFAULT_COLORS)
+foreign import ccall unsafe "use_default_colors" 
+    useDefaultColors :: IO ()
+#else
+useDefaultColors :: IO ()
+useDefaultColors = return ()
+#endif
+
+------------------------------------------------------------------------
+
+--
+-- |> The program must call endwin for each terminal being used before
+-- > exiting from curses.
+--
+endWin :: IO ()
+endWin = throwIfErr_ (P.packAddress "endwin"##) endwin
+
+foreign import ccall unsafe "endwin" 
+    endwin :: IO CInt
+
+------------------------------------------------------------------------
+
+--
+-- | get the dimensions of the screen
+--
+scrSize :: IO (Int, Int)
+scrSize = do
+    lnes <- peek linesPtr
+    cols <- peek colsPtr
+    return (fi lnes, fi cols)
+
+foreign import ccall "&LINES" linesPtr :: Ptr CInt
+foreign import ccall "&COLS"  colsPtr  :: Ptr CInt
+
+--
+-- | refresh curses windows and lines. curs_refresh(3)
+--
+refresh :: IO ()
+refresh = throwIfErr_ (P.packAddress "refresh"##) refresh_c
+
+foreign import ccall unsafe "refresh" 
+    refresh_c :: IO CInt
+
+------------------------------------------------------------------------
+
+hasColors :: IO Bool
+hasColors = liftM (/= 0) has_colors
+
+foreign import ccall unsafe "has_colors" 
+    has_colors :: IO (#type bool)
+
+--
+-- | Initialise the color settings, also sets the screen to the
+-- default colors (white on black)
+--
+startColor :: IO ()
+startColor = throwIfErr_ (P.packAddress "start_color"##) start_color
+
+foreign import ccall unsafe start_color :: IO CInt
+
+newtype Pair  = Pair Int
+newtype Color = Color Int
+
+color :: String -> Maybe Color
+#if defined(HAVE_USE_DEFAULT_COLORS)
+color "default"  = Just $ Color (-1)
+#endif
+color "black"    = Just $ Color (#const COLOR_BLACK)
+color "red"      = Just $ Color (#const COLOR_RED)
+color "green"    = Just $ Color (#const COLOR_GREEN)
+color "yellow"   = Just $ Color (#const COLOR_YELLOW)
+color "blue"     = Just $ Color (#const COLOR_BLUE)
+color "magenta"  = Just $ Color (#const COLOR_MAGENTA)
+color "cyan"     = Just $ Color (#const COLOR_CYAN)
+color "white"    = Just $ Color (#const COLOR_WHITE)
+color _          = Just $ Color (#const COLOR_BLACK)    -- NB
+
+--
+-- |> curses support color attributes  on  terminals  with  that
+-- > capability.   To  use  these  routines start_color must be
+-- > called, usually right after initscr.   Colors  are  always
+-- > used  in pairs (referred to as color-pairs).  A color-pair
+-- > consists of a foreground  color  (for  characters)  and  a
+-- > background color (for the blank field on which the charac-
+-- > ters are displayed).  A programmer  initializes  a  color-
+-- > pair  with  the routine init_pair.  After it has been ini-
+-- > tialized, COLOR_PAIR(n), a macro  defined  in  <curses.h>,
+-- > can be used as a new video attribute.
+--
+-- > If  a  terminal  is capable of redefining colors, the pro-
+-- > grammer can use the routine init_color to change the defi-
+-- > nition   of   a   color.
+--
+-- > The init_pair routine changes the definition of  a  color-
+-- > pair.   It takes three arguments: the number of the color-
+-- > pair to be changed, the foreground color number,  and  the
+-- > background color number.  For portable applications:
+--
+-- > -  The value of the first argument must be between 1 and
+-- >    COLOR_PAIRS-1.
+--
+-- > -  The value of the second and third arguments  must  be
+-- >    between  0  and  COLORS (the 0 color pair is wired to
+-- >    white on black and cannot be changed).
+--
+--
+initPair :: Pair -> Color -> Color -> IO ()
+initPair (Pair p) (Color f) (Color b) =
+    throwIfErr_ (P.packAddress "init_pair"##) $
+        init_pair (fi p) (fi f) (fi b)
+
+foreign import ccall unsafe 
+    init_pair :: CShort -> CShort -> CShort -> IO CInt
+
+-- ---------------------------------------------------------------------
+-- Attributes. Keep this as simple as possible for maximum portability
+
+foreign import ccall unsafe "attrset"
+    c_attrset :: CInt -> IO CInt
+
+attrSet :: Attr -> Pair -> IO ()
+attrSet (Attr attr) (Pair p) = do
+    throwIfErr_ (P.packAddress "attrset"##)   $ c_attrset (attr .|. fi (colorPair p))
+
+------------------------------------------------------------------------
+
+newtype Attr = Attr CInt
+
+attr0   :: Attr
+attr0   = Attr (#const A_NORMAL)
+
+setBold :: Attr -> Bool -> Attr
+setBold = setAttr (Attr #const A_BOLD)
+
+setReverse :: Attr -> Bool -> Attr
+setReverse = setAttr (Attr #const A_REVERSE)
+
+-- | bitwise combination of attributes
+setAttr :: Attr -> Attr -> Bool -> Attr
+setAttr (Attr b) (Attr a) False = Attr (a .&. complement b)
+setAttr (Attr b) (Attr a) True  = Attr (a .|.            b)
+
+attrPlus :: Attr -> Attr -> Attr
+attrPlus (Attr a) (Attr b) = Attr (a .|. b)
+
+------------------------------------------------------------------------
+
+#let translate_attr attr =                              \
+    "(if a .&. %lu /= 0 then %lu else 0) .|.",          \
+    (unsigned long) A_##attr, (unsigned long) A_##attr
+
+bkgrndSet :: Attr -> Pair -> IO ()
+bkgrndSet (Attr a) (Pair p) = bkgdset $
+    fi (ord ' ') .|.
+    #translate_attr ALTCHARSET
+    #translate_attr BLINK
+    #translate_attr BOLD
+    #translate_attr DIM
+    #translate_attr INVIS
+    #translate_attr PROTECT
+    #translate_attr REVERSE
+    #translate_attr STANDOUT
+    #translate_attr UNDERLINE
+    colorPair p
+
+foreign import ccall unsafe "get_color_pair" 
+    colorPair :: Int -> (#type chtype)
+
+foreign import ccall unsafe bkgdset :: (#type chtype) -> IO ()
+
+------------------------------------------------------------------------
+
+foreign import ccall threadsafe
+    waddnstr :: Window -> CString -> CInt -> IO CInt
+
+clrToEol :: IO ()
+clrToEol = throwIfErr_ (P.packAddress "clrtoeol"##) c_clrtoeol
+
+foreign import ccall unsafe "clrtoeol" c_clrtoeol :: IO CInt
+
+--
+-- | >    move the cursor associated with the window
+--   >    to line y and column x.  This routine does  not  move  the
+--   >    physical  cursor  of the terminal until refresh is called.
+--   >    The position specified is relative to the upper  left-hand
+--   >    corner of the window, which is (0,0).
+--
+wMove :: Window -> Int -> Int -> IO ()
+wMove w y x = throwIfErr_ (P.packAddress "wmove"##) $ wmove w (fi y) (fi x)
+
+foreign import ccall unsafe  
+    wmove :: Window -> CInt -> CInt -> IO CInt
+
+-- ---------------------------------------------------------------------
+-- Cursor routines
+
+data CursorVisibility = CursorInvisible | CursorVisible | CursorVeryVisible
+
+--
+-- | Set the cursor state
+--
+-- >       The curs_set routine sets  the  cursor  state  is  set  to
+-- >       invisible, normal, or very visible for visibility equal to
+-- >       0, 1, or 2 respectively.  If  the  terminal  supports  the
+-- >       visibility   requested,   the  previous  cursor  state  is
+-- >       returned; otherwise, ERR is returned.
+--
+cursSet :: CInt -> IO CInt
+cursSet 0 = leaveOk True  >> curs_set 0
+cursSet n = leaveOk False >> curs_set n 
+
+foreign import ccall unsafe "curs_set" 
+    curs_set :: CInt -> IO CInt
+
+-- 
+-- | Get the current cursor coordinates
+--
+getYX :: Window -> IO (Int, Int)
+getYX w =
+    alloca $ \py ->                 -- allocate two ints on the stack
+        alloca $ \px -> do
+            nomacro_getyx w py px   -- writes current cursor coords
+            y <- peek py
+            x <- peek px
+            return (fi y, fi x)
+
+--
+-- | Get the current cursor coords, written into the two argument ints.
+--
+-- >    The getyx macro places the current cursor position of the given
+-- >    window in the two integer variables y and x.
+--
+--      void getyx(WINDOW *win, int y, int x);
+--
+foreign import ccall unsafe "nomacro_getyx" 
+        nomacro_getyx :: Window -> Ptr CInt -> Ptr CInt -> IO ()
+
+--
+-- | >      The getch, wgetch, mvgetch and mvwgetch, routines read a
+--   >      character  from the window.
+--
+foreign import ccall threadsafe getch :: IO CInt
+
+------------------------------------------------------------------------
+--
+-- | Map curses keys to real chars. The lexer will like this.
+--
+decodeKey :: CInt -> Char
+decodeKey = chr . fi
+{-# INLINE decodeKey #-}
+
+--
+-- | Some constants for easy symbolic manipulation.
+-- NB we don't map keys to an abstract type anymore, as we can't use
+-- Alex lexers then.
+--
+keyDown :: Char
+keyDown         = chr (#const KEY_DOWN)
+keyUp :: Char
+keyUp           = chr (#const KEY_UP)
+keyLeft :: Char
+keyLeft         = chr (#const KEY_LEFT)
+keyRight :: Char
+keyRight        = chr (#const KEY_RIGHT)
+
+keyHome :: Char
+keyHome         = chr (#const KEY_HOME)
+keyBackspace :: Char
+keyBackspace    = chr (#const KEY_BACKSPACE)
+
+keyNPage :: Char
+keyNPage        = chr (#const KEY_NPAGE)
+keyPPage :: Char
+keyPPage        = chr (#const KEY_PPAGE)
+keyEnd :: Char
+keyEnd          = chr (#const KEY_END)
+
+#ifdef KEY_RESIZE
+-- ncurses sends this
+keyResize :: Char
+keyResize       = chr (#const KEY_RESIZE)
+#endif
+
+-- ---------------------------------------------------------------------
+-- try to set the upper bits
+
+meta :: Window -> Bool -> IO ()
+meta win bf = throwIfErr_ (P.packAddress "meta"##) $
+    c_meta win (if bf then 1 else 0)
+
+foreign import ccall unsafe "meta" 
+    c_meta :: Window -> CInt -> IO CInt
+
+------------------------------------------------------------------------
+--
+-- | read a character from the window
+--
+-- When 'ESC' followed by another key is pressed before the ESC timeout,
+-- that second character is not returned until a third character is
+-- pressed. wtimeout, nodelay and timeout don't appear to change this
+-- behaviour.
+-- 
+-- On emacs, we really would want Alt to be our meta key, I think.
+--
+-- Be warned, getCh will block the whole process without noDelay
+--
+getCh :: IO Char
+getCh = do
+    threadWaitRead 0
+    v <- getch
+    case v of
+        (#const ERR) -> yield >> getCh
+        x            -> return $ decodeKey x
+
+------------------------------------------------------------------------
+
+#ifdef SIGWINCH
+cursesSigWinch :: Signal
+cursesSigWinch = #const SIGWINCH
+#endif
+
diff --git a/FastIO.hs b/FastIO.hs
new file mode 100644
--- /dev/null
+++ b/FastIO.hs
@@ -0,0 +1,221 @@
+-- 
+-- Copyright (c) 2005-6 Don Stewart - http://www.cse.unsw.edu.au/~dons
+-- 
+-- This program is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation; either version 2 of
+-- the License, or (at your option) any later version.
+-- 
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- General Public License for more details.
+-- 
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+-- 
+
+-- | ByteString versions of some common IO functions
+
+module FastIO where
+
+import Syntax                   (Pretty(ppr))
+
+import qualified Data.ByteString.Char8 as P
+import qualified Data.ByteString as B
+import qualified Data.ByteString.Base as B
+
+import Data.Word                (Word8)
+import Foreign.C.Error
+import Foreign.C.String         (CString)
+import Foreign.C.Types          (CFile, CInt, CLong, CSize)
+import Foreign.Marshal          (allocaBytes, alloca)
+import Foreign.Ptr              (Ptr, nullPtr, castPtr)
+import Foreign.Storable         (peek)
+
+import System.Directory         (Permissions(..))
+import System.IO.Error          (modifyIOError, ioeSetFileName)
+import System.IO.Unsafe         (unsafePerformIO)
+import System.IO                (Handle,hFlush)
+import System.Posix.Internals
+import System.Posix.Types       (Fd, CMode)
+
+import Control.Exception        (catch, bracket)
+
+------------------------------------------------------------------------
+
+-- | Packed string version of basename
+basenameP :: P.ByteString -> P.ByteString
+basenameP fps = case P.elemIndexEnd '/' fps of
+    Nothing -> fps
+    Just i  -> P.drop (i+1) fps
+{-# INLINE basenameP #-}
+
+dirnameP :: P.ByteString -> P.ByteString
+dirnameP fps = case P.elemIndexEnd '/' fps of
+    Nothing -> P.pack "."
+    Just i  -> P.take i fps
+{-# INLINE dirnameP #-}
+
+--
+-- | Packed version of get directory contents
+-- Have them just return CStrings, then pack lazily?
+--
+packedGetDirectoryContents :: P.ByteString -> IO [P.ByteString]
+packedGetDirectoryContents path = do
+  modifyIOError (`ioeSetFileName` (P.unpack path)) $
+   alloca $ \ ptr_dEnt ->
+     bracket
+    (B.useAsCString path $ \s ->
+       throwErrnoIfNullRetry desc (c_opendir s))
+    (\p -> throwErrnoIfMinus1_ desc (c_closedir p))
+    (\p -> loop ptr_dEnt p)
+  where
+    desc = "Utils.packedGetDirectoryContents"
+
+    loop :: Ptr (Ptr CDirent) -> Ptr CDir -> IO [P.ByteString]
+    loop ptr_dEnt dir = do
+      resetErrno
+      r <- readdir dir ptr_dEnt
+      if (r == 0)
+        then do dEnt <- peek ptr_dEnt
+                if (dEnt == nullPtr)
+                    then return []
+                    else do  -- copy entry out before we free:
+                        entry <- B.copyCString =<< d_name dEnt
+                        P.length entry `seq` return ()  -- strictify
+                        freeDirEnt dEnt
+                        entries <- loop ptr_dEnt dir
+                        return $! (entry:entries)
+
+        else do errno <- getErrno
+                if (errno == eINTR)
+                    then loop ptr_dEnt dir
+                    else do let (Errno eo) = errno
+                            if (eo == end_of_dir)
+                                then return []
+                                else throwErrno desc
+
+-- packed version:
+doesFileExist :: P.ByteString -> IO Bool
+doesFileExist name = Control.Exception.catch
+   (packedWithFileStatus "Utils.doesFileExist" name $ \st -> do 
+        b <- isDirectory st; return (not b))
+   (\ _ -> return False)
+
+-- packed version:
+doesDirectoryExist :: P.ByteString -> IO Bool
+doesDirectoryExist name = Control.Exception.catch
+   (packedWithFileStatus "Utils.doesDirectoryExist" name $ \st -> isDirectory st)
+   (\ _ -> return False)
+
+packedWithFileStatus :: String -> P.ByteString -> (Ptr CStat -> IO a) -> IO a
+packedWithFileStatus loc name f = do
+  modifyIOError (`ioeSetFileName` []) $
+    allocaBytes sizeof_stat $ \p -> do
+      B.useAsCString name $ \s -> do    -- i.e. every string is duplicated
+        throwErrnoIfMinus1Retry_ loc (c_stat s p)
+        f p
+
+packedFileNameEndClean :: P.ByteString -> P.ByteString
+packedFileNameEndClean name =
+  if i > 0 && (ec == '\\' || ec == '/') then
+     packedFileNameEndClean (P.take i name)
+   else
+     name
+  where
+      i  = (P.length name) - 1
+      ec = name `P.index` i
+
+isDirectory :: Ptr CStat -> IO Bool
+isDirectory stat = do
+  mode <- st_mode stat
+  return (s_isdir mode)
+
+-- ---------------------------------------------------------------------
+
+-- | Read a line from a file stream connected to an external prcoess,
+-- Returning a ByteString. Note that the underlying C code is dropping
+-- redundant \@F frames for us.
+getFilteredPacket :: Ptr CFile -> IO P.ByteString
+getFilteredPacket fp = B.createAndTrim size $ \p -> do 
+    i <- c_getline p fp
+    if i == -1 
+        then throwErrno "FastIO.packedHGetLine"
+        else return i
+    where
+        size = 1024 + 1 -- seems unlikely
+
+-- convert a Haskell-side Fd to a FILE*.
+fdToCFile :: Fd -> IO (Ptr CFile)
+fdToCFile = c_openfd
+
+-- ---------------------------------------------------------------------
+
+getPermissions :: P.ByteString -> IO Permissions
+getPermissions name = do
+  B.useAsCString name $ \s -> do
+  readp <- c_access s r_OK
+  write <- c_access s w_OK
+  exec  <- c_access s x_OK
+  packedWithFileStatus "FastIO.getPermissions" name $ \st -> do
+  is_dir <- isDirectory st
+  return (
+    Permissions {
+      readable   = readp == 0,
+      writable   = write == 0,
+      executable = not is_dir && exec == 0,
+      searchable = is_dir && exec == 0
+    }
+   )
+
+-- ---------------------------------------------------------------------
+-- | Send a msg over the channel to the decoder
+send :: Pretty a => Handle -> a -> IO ()
+send h m = P.hPut h (ppr m) >> P.hPut h nl >> hFlush h
+    where
+      nl = P.pack "\n"
+
+------------------------------------------------------------------------ 
+
+-- 
+-- A wrapper over printf for use in UI.PTimes
+-- 
+printfPS :: P.ByteString -> Int -> Int -> P.ByteString
+printfPS fmt arg1 arg2 =
+    unsafePerformIO $ B.createAndTrim lim $ \ptr ->
+        B.useAsCString fmt $ \c_fmt -> do
+            sz' <- c_printf2d ptr (fromIntegral lim) (castPtr c_fmt)
+                        (fromIntegral arg1) (fromIntegral arg2)
+            return (min lim (fromIntegral sz')) -- snprintf might truncate
+    where
+      lim = 10 -- NB
+
+-- ---------------------------------------------------------------------
+
+foreign import ccall safe "utils.h forcenext"
+    forceNextPacket :: IO ()
+
+foreign import ccall safe "utils.h getline" 
+    c_getline :: Ptr Word8 -> Ptr CFile -> IO Int
+
+foreign import ccall safe "utils.h openfd"
+    c_openfd  :: Fd -> IO (Ptr CFile)
+
+foreign import ccall unsafe "static string.h strlen" 
+    c_strlen  :: CString -> CInt
+
+foreign import ccall unsafe "static string.h memcpy" 
+    c_memcpy  :: Ptr Word8 -> Ptr Word8 -> Int -> IO ()
+
+foreign import ccall unsafe "__hscore_R_OK" r_OK :: CMode
+foreign import ccall unsafe "__hscore_W_OK" w_OK :: CMode
+foreign import ccall unsafe "__hscore_X_OK" x_OK :: CMode
+
+foreign import ccall unsafe "static stdlib.h strtol" c_strtol
+    :: Ptr Word8 -> Ptr (Ptr Word8) -> Int -> IO CLong
+
+foreign import ccall unsafe "static stdio.h snprintf" 
+    c_printf2d :: Ptr Word8 -> CSize -> Ptr Word8 -> CInt -> CInt -> IO CInt
diff --git a/Keymap.hs b/Keymap.hs
new file mode 100644
--- /dev/null
+++ b/Keymap.hs
@@ -0,0 +1,212 @@
+-- 
+-- Copyright (c) 2004-5 Don Stewart - http://www.cse.unsw.edu.au/~dons
+-- 
+-- This program is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation; either version 2 of
+-- the License, or (at your option) any later version.
+-- 
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- General Public License for more details.
+-- 
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+-- 
+
+--
+-- | Keymap manipulation
+--
+-- The idea of using lazy lexers to implement keymaps is described in
+-- the paper:
+--
+-- >  Dynamic Applications From the Ground Up. Don Stewart and Manuel M.
+-- >  T. Chakravarty. In Proceedings of the ACM SIGPLAN Workshop on
+-- >  Haskell, pages 27-38. ACM Press, 2005.
+-- 
+-- See that for more info.
+--
+module Keymap where
+
+import Prelude hiding (all)
+
+import Core
+import State        (getsST, touchST, HState(helpVisible))
+import Style        (defaultSty, StringA(Fast))
+import qualified UI (resetui)
+import Curses       (keyEnd,keyPPage,keyNPage,keyBackspace,keyHome
+                    ,keyRight,keyLeft,keyUp,keyDown)
+import Lexers       ((>|<),(>||<),action,meta,execLexer
+                    ,alt,with,char,Regexp,Lexer)
+
+import Data.List    ((\\))
+
+import qualified Data.ByteString.Char8 as P (packAddress,ByteString,pack)
+import qualified Data.Map as M (fromList, lookup, Map)
+
+data Search = SearchFile | SearchDir
+
+data Direction = Forwards | Backwards
+
+toBool :: Direction -> Bool
+toBool Forwards = True
+toBool _        = False
+
+type LexerS = Lexer (Search, Direction, String) (IO ())
+
+--
+-- The keymap
+--
+keymap :: [Char] -> [IO ()]
+keymap cs = map (clrmsg >>) actions
+    where (actions,_,_) = execLexer all (cs, defaultS)
+
+defaultS :: (Search, Direction, String)
+defaultS = (SearchDir, Forwards, [])
+
+all :: LexerS
+all = commands >||< search
+
+commands :: LexerS
+commands = (alt keys) `action` \[c] -> Just $ case M.lookup c keyMap of
+        Nothing -> return ()    -- ignore
+        Just a  -> a
+
+------------------------------------------------------------------------
+
+search :: LexerS
+search = searchDir >||< searchFile
+
+searchDir :: LexerS
+searchDir = (char '/' >|< char '?') `meta` \[c] _ ->
+                (with (toggleFocus >> putmsg (Fast (P.pack [c]) defaultSty) >> touchST)
+                ,(SearchDir,if c == '/' then Forwards else Backwards,[c]) ,Just dosearch)
+
+searchFile :: LexerS
+searchFile = (char '\\' >|< char '|') `meta` \[c] _ ->
+                (with (toggleFocus >> putmsg (Fast (P.pack [c]) defaultSty) >> touchST)
+                ,(SearchFile,if c == '\\' then Forwards else Backwards,[c]) ,Just dosearch)
+
+dosearch :: LexerS
+dosearch = search_char >||< search_edit >||< search_esc >||< search_eval
+
+search_char :: LexerS
+search_char = anyButDelNL
+    `meta` \c (t,d,st) ->
+        (with (putmsg (Fast (P.pack(st++c)) defaultSty) >> touchST), (t,d,st++c), Just dosearch)
+    where anyButDelNL = alt $ any' \\ (enter' ++ delete' ++ ['\ESC'])
+
+search_edit :: LexerS
+search_edit = delete
+    `meta` \_ (t,d,st) ->
+        let st' = case st of [c] -> [c]; xs  -> init xs
+        in (with (putmsg (Fast (P.pack st') defaultSty) >> touchST), (t,d,st'), Just dosearch)
+
+-- escape exits ex mode immediately
+search_esc :: LexerS
+search_esc = char '\ESC'
+    `meta` \_ _ -> wrap (clrmsg >> touchST)
+    where wrap a = (with (a >> toggleFocus), defaultS, Just all)
+
+search_eval :: LexerS
+search_eval = enter
+    `meta` \_ (t,d,(_:pat)) -> case pat of
+        [] -> wrap (clrmsg >> touchST)
+        _  -> case t of
+                SearchFile -> wrap (jumpToMatchFile (Just (pat,toBool d)))
+                SearchDir  -> wrap (jumpToMatch     (Just (pat,toBool d)))
+
+    where wrap a = (with (a >> toggleFocus), defaultS, Just all)
+
+------------------------------------------------------------------------
+
+enter', any', digit', delete' :: [Char]
+enter'   = ['\n', '\r']
+delete'  = ['\BS', '\127', keyBackspace ]
+any'     = ['\0' .. '\255']
+digit'   = ['0' .. '9']
+
+delete, enter :: Regexp (Search,Direction,[Char]) (IO ())
+delete  = alt delete'
+enter   = alt enter'
+
+------------------------------------------------------------------------
+
+--
+-- The default keymap, and its description
+--
+keyTable :: [(P.ByteString, [Char], IO ())]
+keyTable =
+    [
+     (p "Move up"#,
+        ['k',keyUp],    up)
+    ,(p "Move down"#,
+        ['j',keyDown],  down)
+    ,(p "Next directory down"#,
+        [keyNPage], jumpToNextDir)
+    ,(p "Next directory up"#,
+        [keyPPage], jumpToPrevDir)
+    ,(p "Jump to start of list"#,
+        [keyHome,'1'],  jump 0)
+    ,(p "Jump to end of list"#,
+        [keyEnd,'G'],   jump maxBound)
+    ,(p "Seek left within song"#,
+        [keyLeft],  seekLeft)
+    ,(p "Seek right within song"#,
+        [keyRight], seekRight)
+    ,(p "Toggle pause"#,
+        ['p'],          pause)
+    ,(p "Play song under cursor"#,
+        ['\n',' '],     play)
+    ,(p "Play previous track"#,
+        ['K'],    playPrev)
+    ,(p "Play next track"#,
+        ['J'],  playNext)
+    ,(p "Toggle the help screen"#,
+        ['h'],   toggleHelp)
+    ,(p "Jump to currently playing song"#,
+        ['t'],   jumpToPlaying)
+    ,(p "Quit (or close help screen)"#,
+        ['q'],   do b <- helpIsVisible ; if b then toggleHelp else quit Nothing)
+    ,(p "Select and play next track"#,
+        ['d'],   playNext >> jumpToPlaying)
+    ,(p "Cycle through normal, random and loop modes"#,
+        ['m'],   nextMode)
+    ,(p "Refresh the display"#,
+        ['\^L'], UI.resetui)
+    ,(p "Repeat last regex search"#,
+        ['n'],   jumpToMatch Nothing)
+    ,(p "Repeat last regex search on files"#,
+        ['N'],   jumpToMatchFile Nothing)
+    ,(p "Load config file"#,
+        ['l'],   loadConfig)
+    ]
+  where
+    -- Keep as Addr#. If we try the pack/packAddress rule, ghc seems to get
+    -- confused and want to *unpack* the strings :/
+    p = P.packAddress
+    {-# INLINE p #-}
+
+extraTable :: [(P.ByteString, [Char])]
+extraTable = [(p "Search for directory matching regex"#, ['/'])
+             ,(p "Search backwards for directory"#, ['?'])
+             ,(p "Search for file matching regex"#, ['\\'])
+             ,(p "Search backwards for file"#, ['|']) ]
+  where
+    -- Keep as Addr#. If we try the pack/packAddress rule, ghc seems to get
+    -- confused and want to *unpack* the strings :/
+    p = P.packAddress
+    {-# INLINE p #-}
+
+
+helpIsVisible :: IO Bool
+helpIsVisible = getsST helpVisible
+
+keyMap :: M.Map Char (IO ())
+keyMap = M.fromList [ (c,a) | (_,cs,a) <- keyTable, c <- cs ]
+
+keys :: [Char]
+keys = concat [ cs | (_,cs,_) <- keyTable ]
diff --git a/Keymap.hs-boot b/Keymap.hs-boot
new file mode 100644
--- /dev/null
+++ b/Keymap.hs-boot
@@ -0,0 +1,8 @@
+module Keymap where
+
+import Data.ByteString
+
+keymap :: [Char] -> [IO ()]
+
+keyTable   :: [(ByteString, [Char], IO ())]
+extraTable :: [(ByteString, [Char])]
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Lexer.hs b/Lexer.hs
new file mode 100644
--- /dev/null
+++ b/Lexer.hs
@@ -0,0 +1,163 @@
+-- 
+-- Copyright (c) 2005 Don Stewart - http://www.cse.unsw.edu.au/~dons
+-- 
+-- This program is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation; either version 2 of
+-- the License, or (at your option) any later version.
+-- 
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- General Public License for more details.
+-- 
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+-- 
+
+-- Lexer for mpg321 messages
+
+module Lexer ( parser ) where
+
+import Syntax   (Msg(..),Status(..),Frame(..),Info(..),Id3(..),File(..),Tag(..))
+import FastIO   (getFilteredPacket)
+
+import Data.Maybe   (fromJust)
+import qualified Data.ByteString.Char8 as P
+
+import Foreign.C.Types  (CFile)
+import Foreign.Ptr      (Ptr)
+
+------------------------------------------------------------------------
+
+doP :: P.ByteString -> Msg
+doP s = S $! case P.head . P.tail $ s of
+                '0' -> Stopped
+                '1' -> Paused
+                '2' -> Playing
+                _ -> error "Invalid Status"
+
+-- Frame decoding status updates (once per frame).
+doF :: P.ByteString -> Msg
+doF s = R $ Frame {
+                currentFrame = readPS (fs !! 0)
+              , framesLeft   = readPS (fs !! 1)
+              , currentTime  = f 2
+              , timeLeft     = f 3
+           }
+        where
+
+          fs  = P.split ' ' . P.tail $ s
+          f n = case P.split '.' (fs !! n) of { [x,y] -> 
+                case readPS x              of { rx    -> 
+                case readPS y              of { ry    -> (rx,ry) }}
+                                              ; _ -> error "doF.f" }
+
+readPS :: P.ByteString -> Int
+readPS = fst . fromJust . P.readInt
+
+-- Outputs information about the mp3 file after loading.
+doS :: P.ByteString -> Msg
+doS s = let fs = P.split ' ' . P.tail $ s
+        in I $ Info {
+            {-
+                  version       = fs !! 0
+                , layer         = read . P.unpack $ fs !! 1
+                , sampleRate    = read . P.unpack $ fs !! 2
+                , playMode      = fs !! 3
+                , modeExtns     = read . P.unpack $ fs !! 4
+                , bytesPerFrame = read . P.unpack $ fs !! 5
+                , channelCount  = read . P.unpack $ fs !! 6
+                , copyrighted   = toEnum (read $ P.unpack (fs !! 7))
+                , checksummed   = toEnum (read $ P.unpack (fs !! 8))
+                , emphasis      = read $ P.unpack $ fs !! 9
+                , bitrate       = read $ P.unpack $ fs !! 10
+                , extension     = read $ P.unpack $ fs !! 11
+            -}
+                userinfo      = P.concat 
+                       [P.pack "mpeg "
+                       ,fs !! 0
+                       ,P.pack " "
+                       ,fs !! 10
+                       ,P.pack "kbit/s "
+                       ,(P.pack . show) ((readPS (fs !! 2)) `div` 1000 :: Int)
+                       ,P.pack "kHz"]
+                }
+
+-- Track info if ID fields are in the file, otherwise file name.
+-- 30 chars per field?
+doI :: P.ByteString -> Msg
+doI s = let f = P.dropSpaceEnd . P.dropSpace . P.tail $ s 
+        in case P.take 4 f of
+            cs | cs == P.pack "ID3:" -> F . File . Right . toId id3 . splitUp . P.drop 4 $ f
+               | otherwise           -> F . File . Left $ f
+    where
+        -- a default
+        id3 :: Id3
+        id3 = Id3 P.empty P.empty P.empty P.empty
+
+        -- break the ID3 string up
+        splitUp :: P.ByteString -> [P.ByteString]
+        splitUp f
+            | f == P.empty  = []
+            | otherwise     
+            = let (a,xs) = P.splitAt 30 f   -- we expect it to be 
+                  xs'    = splitUp xs
+              in a : xs'
+
+        -- and some ugly code:
+        toId :: Id3 -> [P.ByteString] -> Id3
+        toId i ls = 
+            let j = case length ls of
+                    0   -> i
+
+                    1   -> i { id3title  = normalise $! ls !! 0 }
+
+                    2   -> i { id3title  = normalise $! ls !! 0
+                             , id3artist = normalise $! ls !! 1 }
+
+                    _   -> i { id3title  = normalise $! ls !! 0
+                             , id3artist = normalise $! ls !! 1
+                             , id3album  = normalise $! ls !! 2 }
+
+            in j { id3str = (id3artist j)
+                        `maybeJoin`
+                            (id3album j)
+                        `maybeJoin`
+                            (id3title j) }
+
+        maybeJoin t f = if P.null f then t `P.append` P.empty else t `gap` f
+
+        gap x y = P.concat [ x, (P.pack " : "), y ]
+
+        normalise = P.dropSpace . P.dropSpaceEnd
+
+------------------------------------------------------------------------
+
+--
+-- | This function does the most allocations in the long run.
+-- How can we discard most "\@F" input?
+--
+parser :: Ptr CFile -> IO (Either String Msg)
+parser h = do
+    x  <- getFilteredPacket h
+
+    -- normalise the packet
+    let (s,m) = let a    = P.dropWhile (== ' ') x       -- drop any leading whitespace
+                    (b,d)= P.break (== ' ') a           -- split into header and body
+                    b'   = if '@' `P.elem` b 
+                           then P.dropWhile (/= '@') b -- make sure '@' is first char
+                           else b
+                in (P.dropWhile (== '@') b', d)
+
+    return $ case P.head s of
+        'R' -> Right $ T Tag
+        'I' -> Right $ doI m
+        'S' -> Right $ doS m
+        'F' -> Right $ doF m
+        'P' -> Right $ doP m
+        'E' -> Left $ "mpg321 error: " ++ P.unpack x
+        _   -> Left $ "Strange mpg321 packet: " ++ (show (P.unpack x))
+
diff --git a/Lexers.hs b/Lexers.hs
new file mode 100644
--- /dev/null
+++ b/Lexers.hs
@@ -0,0 +1,552 @@
+--  Compiler Toolkit: Self-optimizing lexers
+--
+--  Author : Manuel M. T. Chakravarty
+--  Created: 24 February 95, 2 March 99
+--
+--  Version $Revision: 1.1 $ from $Date: 2002/07/28 03:35:20 $
+--
+--  Copyright (c) [1995..2000] Manuel M. T. Chakravarty
+--  Copyright (c) 2004-5 Don Stewart
+--
+--  This library is free software; you can redistribute it and/or
+--  modify it under the terms of the GNU Library General Public
+--  License as published by the Free Software Foundation; either
+--  version 2 of the License, or (at your option) any later version.
+--
+--  This library is distributed in the hope that it will be useful,
+--  but WITHOUT ANY WARRANTY; without even the implied warranty of
+--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+--  Library General Public License for more details.
+--
+--- DESCRIPTION ---------------------------------------------------------------
+--
+--  Self-optimizing lexer combinators.
+--
+--  For detailed information, see ``Lazy Lexing is Fast'', Manuel
+--  M. T. Chakravarty, in A. Middeldorp and T. Sato, editors, Proceedings of
+--  Fourth Fuji International Symposium on Functional and Logic Programming,
+--  Springer-Verlag, LNCS 1722, 1999.  (See my Web page for details.)
+--
+--             http://www.cse.unsw.edu.au/~chak/papers/Cha99.html
+--
+--  Thanks to Simon L. Peyton Jones <simonpj@microsoft.com> and Roman
+--  Lechtchinsky <wolfro@cs.tu-berlin.de> for their helpful suggestions that
+--  improved the design of this library.
+--
+--- DOCU ----------------------------------------------------------------------
+--
+--  language: Haskell 98
+--
+--  The idea is to combine the benefits of off-line generators with
+--  combinators like in `Parsers.hs' (which builds on Swierstra/Duponcheel's
+--  technique for self-optimizing parser combinators).  In essence, a state
+--  transition graph representing a lexer table is computed on the fly, to
+--  make lexing deterministic and based on cheap table lookups.
+--
+--  Regular expression map to Haskell expressions as follows.  If `x' and `y'
+--  are regular expressions,
+--
+--        -> epsilon
+--    xy  -> x +> y
+--    x*y -> x `star` y
+--    x+y -> x `plus` y
+--    x?y -> x `quest` y
+--
+--  Given such a Haskelized regular expression `hre', we can use
+--
+--    (1) hre `lexaction` \lexeme -> Nothing 
+--    (2) hre `lexaction` \lexeme -> Just token
+--    (3) hre `lexmeta`   \lexeme pos s -> (res, pos', s', Nothing)
+--    (4) hre `lexmeta`   \lexeme pos s -> (res, pos', s', Just l)
+--
+--  where `epsilon' is required at the end of `hre' if it otherwise ends on
+--  `star', `plus', or `quest', and then, we have
+--
+--    (1) discards `lexeme' accepted by `hre',
+--    (2) turns the `lexeme' accepted by `hre' into a token,
+--    (3) while discarding the lexeme accepted by `hre', transforms the
+--        position and/or user state, and
+--    (4) while discarding the lexeme accepted by `hre', transforms the
+--        position and/or user state and returns a lexer to be used for the
+--        next lexeme.
+--
+--  The component `res' in case of a meta action, can be `Nothing', `Just
+--  (Left err)', or `Just (Right token)' to return nothing, an error, or a
+--  token from a meta action, respectively.
+--
+--  * This module makes essential use of graphical data structures (for
+--    representing the state transition graph) and laziness (for maintaining
+--    the last action in `execLexer'.
+--
+--  NOTES:
+--
+--  * In this implementation, the combinators `quest`, `star`, and `plus` are
+--    *right* associative - this was different in the ``Lazy Lexing is Fast''
+--    paper.  This change was made on a suggestion by Martin Norbäck
+--    <d95mback@dtek.chalmers.se>.
+--
+--- TODO ----------------------------------------------------------------------
+--
+--  * error correction is missing
+--
+--  * in (>||<) in the last case, `(addBoundsNum bn bn')' is too simple, as
+--    the number of outgoing edges is not the sum of the numbers of the
+--    individual states when there are conflicting edges, ie, ones labeled
+--    with the same character; however, the number is only used to decide a
+--    heuristic, so it is questionable whether it is worth spending the
+--    additional effort of computing the accurate number
+--
+--  * Unicode posses a problem as the character domain becomes too big for
+--    using arrays to represent transition tables and even sparse structures
+--    will posse a significant overhead when character ranges are naively
+--    represented.  So, it might be time for finite maps again.  
+--
+--    Regarding the character ranges, there seem to be at least two
+--    possibilities.  Doaitse explicitly uses ranges and avoids expanding
+--    them.  The problem with this approach is that we may only have
+--    predicates such as `isAlphaNum' to determine whether a givne character
+--    belongs to some character class.  From this representation it is
+--    difficult to efficiently compute a range.  The second approach, as
+--    proposed by Tom Pledger <Tom.Pledger@peace.com> (on the Haskell list)
+--    would be to actually use predicates directly and make the whole business
+--    efficient by caching predicate queries.  In other words, for any given
+--    character after we have determined (in a given state) once what the
+--    following state on accepting that character is, we need not consult the
+--    predicates again if we memorise the successor state the first time
+--    around.
+--
+
+module Lexers (
+
+   Regexp, Lexer, Action, Meta, Error, 
+   epsilon, char, (+>), 
+   lexaction, lexactionErr, lexmeta, action, meta,
+   (>|<), (>||<), 
+   star, plus, quest, alt, string, with, LexerState, execLexer
+
+   ) where 
+
+import Prelude hiding   (last)
+import Data.Maybe       (fromMaybe)
+import Data.Array       (Array, (!), assocs, accumArray)
+
+infixr 4 `quest`, `star`, `plus`
+infixl 3 +>, `lexaction`, `lexmeta`, `action`, `meta`
+infixl 2 >|<, >||<
+
+-- constants
+-- ---------
+
+-- we use the dense representation if a table has at least the given number of 
+-- (non-error) elements
+--
+denseMin :: Int
+denseMin  = 20
+
+
+-- data structures
+-- ---------------
+
+-- represents the number of (non-error) elements and the bounds of a table
+--
+type BoundsNum = (Int, Char, Char)
+
+-- empty bounds
+--
+-- nullBoundsNum :: BoundsNum
+-- nullBoundsNum  = (0, maxBound, minBound)
+
+-- combine two bounds
+--
+addBoundsNum                            :: BoundsNum -> BoundsNum -> BoundsNum
+addBoundsNum (n, lc, hc) (n', lc', hc')  = (n + n', min lc lc', max hc hc')
+
+-- check whether a character is in the bounds
+--
+inBounds               :: Char -> BoundsNum -> Bool
+inBounds c (_, lc, hc)  = c >= lc && c <= hc
+
+-- Lexer errors
+type Error = String
+
+-- Lexical actions take a lexeme with its position and may return a token; in
+-- a variant, an error can be returned (EXPORTED)
+--
+-- * if there is no token returned, the current lexeme is discarded lexing
+--   continues looking for a token
+--
+type Action    t = String -> Maybe t
+type ActionErr t = String -> Either Error t
+
+-- Meta actions transform the lexeme, and a user-defined state; they
+-- may return a lexer, which is then used for accepting the next token
+-- (this is important to implement non-regular behaviour like nested
+-- comments) (EXPORTED) 
+--
+type Meta s t = String -> s -> (Maybe (Either Error t), -- err/tok?
+                                s,                      -- state
+                                Maybe (Lexer s t))      -- lexer?
+
+-- tree structure used to represent the lexer table (EXPORTED ABSTRACTLY) 
+--
+-- * each node in the tree corresponds to a state of the lexer; the associated 
+--   actions are those that apply when the corresponding state is reached
+--
+data Lexer s t = Lexer (LexAction s t) (Cont s t)
+
+-- represent the continuation of a lexer
+--
+data Cont s t = -- on top of the tree, where entries are dense, we use arrays
+                --
+                Dense BoundsNum (Array Char (Lexer s t))
+                --
+                -- further down, where the valid entries are sparse, we
+                -- use association lists, to save memory (the first argument
+                -- is the length of the list)
+                --
+              | Sparse BoundsNum [(Char, Lexer s t)]
+                --
+                -- end of a automaton
+                --
+              | Done
+
+-- lexical action (EXPORTED ABSTRACTLY)
+--
+data LexAction s t = Action   (Meta s t)
+                   | NoAction
+
+-- a regular expression (EXPORTED)
+--
+type Regexp s t = Lexer s t -> Lexer s t
+
+
+-- basic combinators
+-- -----------------
+
+-- Empty lexeme (EXPORTED)
+--
+epsilon :: Regexp s t
+epsilon  = id
+
+-- One character regexp (EXPORTED) 
+--
+char   :: Char -> Regexp s t
+char c  = \l -> Lexer NoAction (Sparse (1, c, c) [(c, l)])
+
+-- Concatenation of regexps (EXPORTED)
+--
+(+>) :: Regexp s t -> Regexp s t -> Regexp s t
+(+>)  = (.)
+
+-- Close a regular expression with an action that converts the lexeme into a
+-- token (EXPORTED)
+--
+-- * Note: After the application of the action, the position is advanced
+--         according to the length of the lexeme.  This implies that normal
+--         actions should not be used in the case where a lexeme might contain 
+--         control characters that imply non-standard changes of the position, 
+--         such as newlines or tabs.
+--
+action :: Regexp s t -> Action t -> Lexer s t
+action = lexaction
+
+lexaction      :: Regexp s t -> Action t -> Lexer s t
+lexaction re a  = re `lexmeta` a'
+  where
+    a' lexeme s = 
+       case a lexeme of
+            Nothing -> (Nothing, s, Nothing)
+            Just t  -> (Just (Right t), s, Nothing)
+
+-- Variant for actions that may returns an error (EXPORTED)
+--
+lexactionErr      :: Regexp s t -> ActionErr t -> Lexer s t
+lexactionErr re a  = re `lexmeta` a'
+  where
+     a' lexeme s = (Just (a lexeme), s, Nothing)
+
+-- Close a regular expression with a meta action (EXPORTED)
+--
+-- * Note: Meta actions have to advance the position in dependence of the
+--         lexeme by themselves.
+--
+meta :: Regexp s t -> Meta s t -> Lexer s t
+meta = lexmeta
+
+lexmeta      :: Regexp s t -> Meta s t -> Lexer s t
+lexmeta re a  = re (Lexer (Action a) Done)
+
+-- useful for building meta actions
+with :: b -> Maybe (Either a b)
+with a = Just (Right a)
+
+-- disjunctive combination of two regexps (EXPORTED)
+--
+(>|<)      :: Regexp s t -> Regexp s t -> Regexp s t
+re >|< re'  = \l -> re l >||< re' l
+
+-- disjunctive combination of two lexers (EXPORTED)
+--
+(>||<)                         :: Lexer s t -> Lexer s t -> Lexer s t
+(Lexer a c) >||< (Lexer a' c')  = Lexer (joinActions a a') (joinConts c c')
+
+-- combine two disjunctive continuations
+--
+joinConts :: Cont s t -> Cont s t -> Cont s t
+joinConts Done c'   = c'
+joinConts c    Done = c
+joinConts c    c'   = let (bn , cls ) = listify c
+                          (bn', cls') = listify c'
+                      in
+                      -- note: `addsBoundsNum' can, at this point, only
+                      --       approx. the number of *non-overlapping* cases;
+                      --       however, the bounds are correct 
+                      --
+                      aggregate (addBoundsNum bn bn') (cls ++ cls')
+  where
+    listify (Dense  n arr) = (n, assocs arr)
+    listify (Sparse n cls) = (n, cls)
+    listify _              = error "Lexers.listify: Impossible argument!"
+
+-- combine two actions. Use the latter in case of overlap (!)
+--
+joinActions :: LexAction s t -> LexAction s t -> LexAction s t
+joinActions NoAction a'       = a'
+joinActions a        NoAction = a
+joinActions _        a'       = a' -- error "Lexers.>||<: Overlapping actions!"
+
+-- Note: `n' is only an upper bound of the number of non-overlapping cases
+--
+aggregate :: BoundsNum -> ([(Char, Lexer s t)]) -> Cont s t
+aggregate bn@(n, lc, hc) cls
+  | n >= denseMin = Dense  bn (accumArray (>||<) noLexer (lc, hc) cls)
+  | otherwise     = Sparse bn (accum (>||<) cls)
+  where
+    noLexer = Lexer NoAction Done
+
+-- combine the elements in the association list that have the same key
+--
+accum :: Eq a => (b -> b -> b) -> [(a, b)] -> [(a, b)]
+accum _ []           = []
+accum f ((c, el):ces) = 
+  let (ce, ces') = gather c el ces
+  in ce : accum f ces'
+  where
+    gather k e []                             = ((k, e), [])
+    gather k e (ke'@(k', e'):kes) | k == k'   = gather k (f e e') kes
+                                  | otherwise = let 
+                                                  (ke'', kes') = gather k e kes
+                                                in
+                                                (ke'', ke':kes')
+
+
+-- non-basic combinators
+-- ---------------------
+
+-- x `star` y corresponds to the regular expression x*y (EXPORTED)
+--
+star :: Regexp s t -> Regexp s t -> Regexp s t
+--
+-- The definition used below can be obtained by equational reasoning from this
+-- one (which is much easier to understand): 
+--
+--   star re1 re2 = let self = (re1 +> self >|< epsilon) in self +> re2
+--
+-- However, in the above, `self' is of type `Regexp s t' (ie, a functional),
+-- whereas below it is of type `Lexer s t'.  Thus, below we have a graphical
+-- body (finite representation of an infinite structure), which doesn't grow
+-- with the size of the accepted lexeme - in contrast to the definition using
+-- the functional recursion.
+--
+star re1 re2  = \l -> let self = re1 self >||< re2 l
+                      in 
+                      self
+
+-- x `plus` y corresponds to the regular expression x+y (EXPORTED)
+--
+plus         :: Regexp s t -> Regexp s t -> Regexp s t
+plus re1 re2  = re1 +> (re1 `star` re2)
+
+-- x `quest` y corresponds to the regular expression x?y (EXPORTED)
+--
+quest         :: Regexp s t -> Regexp s t -> Regexp s t
+quest re1 re2  = (re1 +> re2) >|< re2
+
+-- accepts a non-empty set of alternative characters (EXPORTED)
+--
+alt    :: [Char] -> Regexp s t
+--
+--  Equiv. to `(foldr1 (>|<) . map char) cs', but much faster
+--
+alt []  = error "Lexers.alt: Empty character set!"
+alt cs  = \l -> let bnds = (length cs, minimum cs, maximum cs)
+                in
+                Lexer NoAction (aggregate bnds [(c, l) | c <- cs])
+
+-- accept a character sequence (EXPORTED)
+--
+string    :: String -> Regexp s t
+string []  = error "Lexers.string: Empty character set!"
+string cs  = (foldr1 (+>) . map char) cs
+
+
+-- execution of a lexer
+-- --------------------
+
+-- threaded top-down during lexing (current input, meta state) (EXPORTED)
+--
+type LexerState s = (String, s)
+
+-- apply a lexer, yielding a token sequence and a list of errors (EXPORTED)
+--
+-- * Currently, all errors are fatal; thus, the result is undefined in case of 
+--   an error (this changes when error correction is added).
+--
+-- * The final lexer state is returned.
+--
+-- * The order of the error messages is undefined.
+--
+execLexer :: Lexer s t -> LexerState s -> ([t], LexerState s, [Error])
+--
+-- * the following is moderately tuned
+--
+execLexer _ st@([], _) = ([], st, [])
+execLexer l st = 
+  case lexOne l st of
+    (Nothing , _ , st') -> execLexer l st'
+    (Just res, l', st') -> let (ts, final, allErrs) = execLexer l' st'
+                           in case res of
+                                (Left  err) -> (ts  , final, err:allErrs)
+                                (Right t  ) -> (t:ts, final, allErrs)
+  where
+    -- accept a single lexeme
+    --
+    -- lexOne :: Lexer s t -> LexerState s t
+    --        -> (Either Error (Maybe t), Lexer s t, LexerState s t)
+    lexOne l0 st' = oneLexeme l0 st' zeroDL lexErr
+
+      where
+        -- the result triple of `lexOne' that signals a lexical error;
+        -- the result state is advanced by one character for error correction
+        --
+        lexErr = let (cs, s) = st'
+                     err = "Lexical error!\n" ++
+                           "The character " ++ show (head cs) 
+                              ++ " does not fit here; skipping it."
+                 in
+                 (Just (Left err), l, (tail cs, s))
+
+        --
+        -- we take an open list of characters down, where we accumulate the
+        -- lexeme; this function returns maybe a token, the next lexer to use
+        -- (can be altered by a meta action), the new lexer state, and a list
+        -- of errors
+        --
+        -- we implement the "principle of the longest match" by taking a
+        -- potential result quadruple down (in the last argument); the
+        -- potential result quadruple is updated whenever we pass by an action 
+        -- (different from `NoAction'); initially it is an error result
+        --
+
+        -- (dons): from the paper "we have to take the last possible
+        -- action before the automaton gets stuck. .. when no further
+        -- transition is possible, we execute the last action on the
+        -- associated lexeme." This means that even once all possible
+        -- actions have been looked at, we currently then wait till the
+        -- _next_ char, before returning the last action we're carrying
+        -- around. For interactive use, we instead need to execute the
+        -- last action once we encounter it, not once we've gone past
+        -- it. Hmm...
+
+        --
+        -- oneLexeme :: Lexer s t
+        --           -> LexerState
+        --           -> DList Char 
+        --           -> (Maybe (Either Error t), Maybe (Lexer s t), 
+        --               LexerState s t)
+        --           -> (Maybe (Either Error t), Maybe (Lexer s t), 
+        --               LexerState s t)
+        --
+        oneLexeme (Lexer a cont) state@(cs, s) csDL last =
+            let last' = doaction a csDL state last
+            in case cs of
+                []      -> last'    -- at end, has to be this action
+                (c:cs') -> oneChar cont c (cs', s) csDL last'   -- keep looking
+
+        --
+        -- There are more chars. Look at the next one
+        --
+        -- Now, if the next tbl is Done, then there is no more
+        -- transition, so immediately execute our action
+        --
+        oneChar tbl c state csDL last = 
+            case peek tbl c of
+                Nothing              -> last
+                Just (Lexer a Done)  -> doaction a (csDL `snocDL` c) state last
+                Just l'              -> continue l' c state csDL last
+
+        --
+        -- Do the lookup.
+        --
+        peek Done _ = Nothing
+        peek (Dense bn arr)  c | c `inBounds` bn = Just $ arr ! c
+        peek (Sparse bn cls) c | c `inBounds` bn = lookup c cls
+        peek _ _    = Nothing
+
+        --
+        -- continue within the current lexeme
+        --
+        continue l' c state csDL last = 
+            oneLexeme l' state (csDL `snocDL` c) last
+
+        --
+        -- execute the action if present and finalise the current lexeme
+        --
+        doaction (Action f) csDL (cs, s) _last = 
+            case f (closeDL csDL) s of
+                (Nothing, s', l') 
+                    | not . null $ cs -> lexOne (fromMaybe l0 l') (cs, s')
+                (res, s', l')         -> (res, (fromMaybe l0 l'), (cs, s'))
+
+        doaction NoAction _csDL _state last = last -- no change
+
+------------------------------------------------------------------------
+--
+--  This module provides the functional equivalent of the difference lists
+--  from logic programming.  They provide an O(1) append.
+--
+
+
+-- | a difference list is a function that given a list returns the original
+-- contents of the difference list prepended at the given list (EXPORTED)
+type DList a = [a] -> [a]
+
+-- | open a list for use as a difference list (EXPORTED)
+{-
+openDL :: [a] -> DList a
+openDL  = (++)
+-}
+
+-- | create a difference list containing no elements (EXPORTED)
+zeroDL :: DList a
+zeroDL  = id
+
+-- | create difference list with given single element (EXPORTED)
+{-
+unitDL :: a -> DList a
+unitDL  = (:)
+-}
+
+-- | append a single element at a difference list (EXPORTED)
+snocDL      :: DList a -> a -> DList a
+snocDL dl x  = \l -> dl (x:l)
+
+-- | appending difference lists (EXPORTED)
+{-
+joinDL :: DList a -> DList a -> DList a
+joinDL  = (.)
+-}
+
+-- | closing a difference list into a normal list (EXPORTED)
+closeDL :: DList a -> [a]
+closeDL  = ($[])
diff --git a/Main.hs b/Main.hs
new file mode 100644
--- /dev/null
+++ b/Main.hs
@@ -0,0 +1,105 @@
+-- 
+-- Copyright (c) Don Stewart 2004-5.
+-- Copyright (c) Tuomo Valkonen 2004.
+--
+-- This program is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation; either version 2 of
+-- the License, or (at your option) any later version.
+-- 
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- General Public License for more details.
+-- 
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+-- 
+
+module Main where
+
+import Core     (start, readSt, shutdown)
+import Tree     (SerialT(..))
+import Utils    ((<+>))
+import Config   (darcsinfo, help, versinfo)
+import Keymap   ({-# bogus import to work around 6.4 rec modules bug #-})
+
+import qualified Data.ByteString.Char8 as P (pack,ByteString,getArgs)
+
+import Control.Exception    (catch)
+
+import System.IO            (hPutStrLn, stderr)
+import System.Exit          (ExitCode(..), exitWith)
+import System.Posix.Signals (installHandler, sigTERM, sigPIPE, sigINT, sigHUP
+                            ,sigALRM, sigABRT, Handler(Ignore, Default, Catch))
+
+-- ---------------------------------------------------------------------
+-- | Set up the signal handlers
+
+--
+-- Notes on setStoppedChildFlag:
+--      If this bit is set when installing a catching function for the SIGCHLD
+--      signal, the SIGCHLD signal will be generated only when a child process
+--      exits, not when a child process stops.
+--
+-- setStoppedChildFlag True
+--
+initSignals :: IO ()
+initSignals = do 
+
+    -- ignore
+    flip mapM_ [sigPIPE, sigALRM] 
+               (\sig -> installHandler sig Ignore Nothing)
+
+    -- and exit if we get the following:
+    flip mapM_ [sigINT, sigHUP, sigABRT, sigTERM] $ \sig -> do
+            installHandler sig (Catch (do
+                Control.Exception.catch (shutdown Nothing) (\f -> hPutStrLn stderr (show f))
+                exitWith (ExitFailure 1) )) Nothing
+
+releaseSignals :: IO ()
+releaseSignals =
+    flip mapM_ [sigINT, sigPIPE, sigHUP, sigABRT, sigTERM] 
+               (\sig -> installHandler sig Default Nothing)
+
+------------------------------------------------------------------------
+-- | Argument parsing.
+
+-- usage string.
+usage :: [String]
+usage = ["Usage: hmp3 [-Vh] [FILE|DIR ...]"
+        ,"-V  --version  Show version information"
+        ,"-h  --help     Show this help"]
+
+-- | Parse the args
+do_args :: [P.ByteString] -> IO (Either SerialT [P.ByteString])
+do_args []  = do    -- attempt to read db
+    x <- readSt 
+    case x of
+        Nothing -> do mapM_ putStrLn usage; exitWith ExitSuccess
+        Just st -> return $ Left st
+
+do_args [s] | s == P.pack "-V"  || s == P.pack "--version"
+            = do putStrLn (versinfo <+> help); putStrLn darcsinfo; exitWith ExitSuccess
+            | s == P.pack "-h"  || s == P.pack "--help"
+            = do putStrLn (versinfo <+> help); mapM_ putStrLn usage; exitWith ExitSuccess
+
+do_args xs = return $ Right xs
+
+-- ---------------------------------------------------------------------
+-- | Static main. This is the front end to the statically linked
+-- application, and the real front end, in a sense. 'dynamic_main' calls
+-- this after setting preferences passed from the boot loader.
+--
+-- Initialise the ui getting an initial editor state, set signal
+-- handlers, then jump to ui event loop with the state.
+--
+main :: IO ()
+main = do  
+    args  <- P.getArgs
+    files <- do_args args
+    initSignals
+    start files -- never returns
+
diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,97 @@
+
+            hmp3 : an ncurses mp3 player written in Haskell
+          ---------------------------------------------------
+
+Dependencies:
+    The Glasgow Haskell Compiler >= 6.4.2     http://haskell.org/ghc
+    mpg321                                    http://mpg321.sourceforge.net/
+    A version of FPS >= 0.7                   http://www.cse.unsw.edu.au/~dons/fps.html
+    A Cabal newer than 1.0                    http://haskell.org/cabal
+    curses
+
+Building:
+    $ chmod +x configure Setup.hs
+    $ ./Setup.hs configure --prefix=/home/dons
+    $ ./Setup.hs build
+    $ ./Setup.hs install
+
+This assumes you have Cabal installed. Cabal is installed by default
+with newer GHCs. If your Cabal version is too old (v1.0 that comes with
+GHC 6.4.1 is too old), or if you see:
+      dist/build/hmp3-tmp/cbits/utils.o: No such file or directory
+errors, then you need to download a newer Cabal version first.
+
+Use:
+    To populate a playlist, and start:
+
+    $ hmp3 ~/mp3/dir/
+     or
+    $ hmp3 a.mp3 b.mp3
+
+    From then on this playlist is saved in ~/.hmp3db, and is reloaded
+    automatically, if you restart hmp3 with no arguments.
+
+    $ hmp3
+
+    Type 'h' to display the help page. The other commands are explained
+    on the help screen, which can be accessed by typing 'h'. Quit with
+    'q'.
+
+Configuration:
+
+    Colours may be configured at runtime by editing the "~/.hmp3" file.
+    An example would be:
+
+        Config { 
+                 hmp3_window      = ("brightwhite", "black")
+               , hmp3_helpscreen  = ("black",       "cyan")
+               , hmp3_titlebar    = ("green",       "blue")
+               , hmp3_selected    = ("brightwhite", "black")
+               , hmp3_cursors     = ("black",       "cyan")
+               , hmp3_combined    = ("black",       "cyan")
+               , hmp3_warnings    = ("brightwhite", "red")
+               , hmp3_blockcursor = ("black",       "darkred")
+               , hmp3_progress    = ("cyan",        "white")
+             }
+
+    After editing this file, hit 'l' to have the changes used by hmp3.
+
+    The keymaps are configurable by adding your own bindings to
+    Config.hs (as are the colours). Edit this file before compilation.
+
+    Alternatively, you can switch betwee dark and light settings without
+    recompiling. If you have a light xterm, set HMP_HAS_LIGHT_BG=true in
+    your shell, and hmp3 will use the light color settings by default.
+
+Limitations:
+    It only plays mp3 files (and variants supported by mpg{321,123}.
+    So no ogg files for now. This is on the todo list though.
+
+    It is possible to use mpg123, however it appears to be more error
+    prone, and less stable than mpg321.
+
+Platforms and portability:
+    hmp3 has been confirmed to work on:
+        OpenBSD/x86
+        Linux/x86
+        FreeBSD/x86
+        Linux/ppc
+        MacOSX/ppc
+        Irix/mips64
+
+    * You need -threaded.
+
+    * On platforms without a native code generator, you should remove the
+    reference to -fasm in the hmp3.cabal file
+
+License:
+    GPL
+
+Author:
+    Don Stewart, Tue Jun 27 17:11:03 EST 2006
+
+Contributors:
+    Samuel Bronson
+    Stefan Wehr
+    Tomasz Zielonka
+    David Himmelstrup
diff --git a/Regex.hsc b/Regex.hsc
new file mode 100644
--- /dev/null
+++ b/Regex.hsc
@@ -0,0 +1,133 @@
+--
+--
+-- Module      :  Text.Regex.Posix
+--
+-- Copyright   :  (c) The University of Glasgow 2002
+--                (c) Don Stewart 2004
+--
+-- License     :  BSD-style (see the file libraries/base/LICENSE)
+-- 
+-- Maintainer  :  libraries@haskell.org
+-- Stability   :  experimental
+-- Portability :  portable
+--
+
+--  
+-- | Interface to the POSIX regular expression library.
+--
+
+module Regex (
+
+    -- * The @Regex@ type
+    Regex,      -- abstract
+
+    -- * Compiling a regular expression
+    regcomp,    -- :: String -> Int -> IO Regex
+
+    -- ** Flags for regcomp
+    regExtended,    -- (flag to regcomp) use extended regex syntax
+    regIgnoreCase,  -- (flag to regcomp) ignore case when matching
+    regNewline,     -- (flag to regcomp) '.' doesn't match newline
+    regNosub,       -- unused
+
+    -- * Matching a regular expression
+    regexec,        -- :: Regex -> Ptr CChar -> Int
+                    -- -> IO (Maybe ((Int,Int), [(Int,Int)]))
+
+  ) where
+
+#include "config.h"
+
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#if HAVE_REGEX_H
+# include <regex.h>
+#endif
+
+import Foreign.C
+import Foreign
+
+type CRegex = ()
+
+-- | A compiled regular expression
+newtype Regex = Regex (ForeignPtr CRegex)
+
+-- ---------------------------------------------------------------------
+-- | Compiles a regular expression
+--
+regcomp :: String     -- ^ The regular expression to compile
+        -> Int        -- ^ Flags (summed together)
+        -> IO Regex   -- ^ Returns: the compiled regular expression
+
+regcomp pattern flags = do
+    regex_fptr <- mallocForeignPtrBytes (#const sizeof(regex_t))
+    r <- withCString pattern $ \cstr ->
+        withForeignPtr regex_fptr $ \p ->
+            c_regcomp p cstr (fromIntegral flags)
+    if (r == 0)
+        then do
+             addForeignPtrFinalizer ptr_regfree regex_fptr
+             return (Regex regex_fptr)
+        else ioError $ userError $ "Error in pattern: " ++ pattern
+
+-- ---------------------------------------------------------------------
+-- | Matches a regular expression against a buffer, returning the buffer
+-- indicies of the match, and any submatches
+--
+regexec :: Regex                -- ^ Compiled regular expression
+        -> Ptr CChar            -- ^ The buffer to match against
+        -> Int                  -- ^ Offset in buffer to start searching from
+        -> IO (Maybe ((Int,Int), [(Int,Int)]))
+        -- ^ Returns: 'Nothing' if the regex did not match the
+        -- or Just the start and end indicies of the match and submatches
+
+regexec (Regex regex_fptr) ptr i = do
+    withForeignPtr regex_fptr $ \regex_ptr -> do
+        nsub <- (#peek regex_t, re_nsub) regex_ptr
+        let nsub_int = fromIntegral (nsub :: CSize)
+        allocaBytes ((1 + nsub_int)*(#const sizeof(regmatch_t))) $ \p_match-> do
+            -- add one because index zero covers the whole match
+            r <- cregexec regex_ptr (ptr `plusPtr` i) 
+                                    (1 + nsub) p_match 0{-no flags -}
+
+            if (r /= 0) then return Nothing else do 
+                match       <- indexOfMatch p_match
+                sub_matches <- mapM (indexOfMatch) $ take nsub_int $ tail $
+                        iterate (`plusPtr` (#const sizeof(regmatch_t))) p_match
+
+                return (Just (match, sub_matches))
+
+indexOfMatch :: Ptr CRegMatch -> IO (Int, Int)
+indexOfMatch p_match = do
+    start <- (#peek regmatch_t, rm_so) p_match :: IO (#type regoff_t)
+    end   <- (#peek regmatch_t, rm_eo) p_match :: IO (#type regoff_t)
+    let s = fromIntegral start; e = fromIntegral end
+    return (s, e)
+
+-- -----------------------------------------------------------------------------
+-- The POSIX regex C interface
+
+regExtended :: Int
+regExtended =  1
+regIgnoreCase  :: Int
+regIgnoreCase  =  2
+regNosub :: Int
+regNosub =  4
+regNewline :: Int
+regNewline =  8
+
+type CRegMatch = ()
+
+foreign import ccall unsafe "regex.h regcomp"
+    c_regcomp :: Ptr CRegex -> CString -> CInt -> IO CInt
+
+foreign import ccall  unsafe "regex.h &regfree"
+    ptr_regfree :: FunPtr (Ptr CRegex -> IO ())
+
+foreign import ccall unsafe "regex.h regexec"
+    cregexec :: Ptr CRegex 
+             -> Ptr CChar 
+             -> CSize -> Ptr CRegMatch -> CInt -> IO CInt
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+#!/usr/bin/env runhaskell
+import Distribution.Simple
+main = defaultMainWithHooks defaultUserHooks
diff --git a/State.hs b/State.hs
new file mode 100644
--- /dev/null
+++ b/State.hs
@@ -0,0 +1,162 @@
+-- 
+-- Copyright (c) 2004-5 Don Stewart - http://www.cse.unsw.edu.au/~dons
+-- 
+-- This program is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation; either version 2 of
+-- the License, or (at your option) any later version.
+-- 
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- General Public License for more details.
+-- 
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+-- 
+
+--
+-- | The top level application state, and operations on that value.
+--
+module State where
+
+import Syntax                   (Status(Stopped), Mode(..), Frame, Info,Id3)
+import Tree                     (FileArray, DirArray)
+import Style                    (StringA(Fast), defaultSty, UIStyle)
+import Regex                    (Regex)
+import qualified Data.ByteString as P (empty,ByteString)
+import qualified Config (defaultStyle)
+
+import Data.Array               (listArray)
+import System.IO.Unsafe         (unsafePerformIO)
+import System.Posix.Types       (ProcessID)
+import System.Time              (ClockTime(..))
+import System.IO                (Handle)
+import Foreign.C.Types          (CFile)
+import Foreign.Ptr              (Ptr)
+
+import Control.Concurrent       (ThreadId)
+import Control.Concurrent.MVar
+
+-- import Control.Monad.State
+
+------------------------------------------------------------------------
+-- A state monad over IO would be another option.
+
+-- type ST = StateT HState IO
+
+------------------------------------------------------------------------
+
+-- | The editor state type
+data HState = HState {
+        music           :: !FileArray
+       ,folders         :: !DirArray
+       ,size            :: !Int                  -- cache size of list
+       ,current         :: !Int                  -- currently playing mp3
+       ,cursor          :: !Int                  -- mp3 under the cursor
+       ,clock           :: !(Maybe Frame)        -- current clock value
+       ,clockUpdate     :: !Bool
+       ,mp3pid          :: !(Maybe ProcessID)    -- pid of decoder
+       ,writeh          :: !(MVar Handle)        --  handle to mp3 (should be MVars?)
+       ,errh            :: !(MVar Handle)        --  error handle to mp3
+       ,readf           :: !(MVar (Ptr CFile))   -- r/w pipe to mp3
+       ,threads         :: ![ThreadId]           -- all our threads
+       ,id3             :: !(Maybe Id3)          -- maybe mp3 id3 info
+       ,info            :: !(Maybe Info)         -- mp3 info
+       ,status          :: !Status
+       ,minibuffer      :: !StringA              -- contents of minibuffer
+       ,helpVisible     :: !Bool                 -- is the help window shown
+       ,miniFocused     :: !Bool                 -- is the mini buffer focused?
+       ,mode            :: !Mode                 -- random mode
+       ,uptime          :: !P.ByteString
+       ,boottime        :: !ClockTime
+       ,regex           :: !(Maybe (Regex,Bool)) -- most recent search pattern and direction
+       ,xterm           :: !Bool
+       ,doNotResuscitate:: !Bool                -- should we just let mpg321 die?
+       ,config          :: !UIStyle             -- config values
+
+       ,modified        :: !(MVar ())           -- Set when redrawable components of 
+                                                -- the state are modified. The ui
+                                                -- refresh thread waits on this.
+    }
+
+------------------------------------------------------------------------
+--
+-- | The initial state
+--
+emptySt :: HState
+emptySt = HState {
+        music        = listArray (0,0) []
+       ,folders      = listArray (0,0) []
+
+       ,size         = 0
+       ,current      = 0
+       ,cursor       = 0
+
+       ,threads      = []
+       ,modified     = unsafePerformIO newEmptyMVar
+       ,writeh       = unsafePerformIO newEmptyMVar
+       ,errh         = unsafePerformIO newEmptyMVar
+       ,readf        = unsafePerformIO newEmptyMVar
+
+       ,mp3pid       = Nothing
+       ,clock        = Nothing
+       ,info         = Nothing
+       ,id3          = Nothing
+       ,regex        = Nothing
+
+       ,clockUpdate      = False
+       ,helpVisible      = False
+       ,miniFocused      = False
+       ,xterm            = False
+       ,doNotResuscitate = False    -- mgp321 should be be restarted
+
+       ,config       = Config.defaultStyle
+       ,boottime     = TOD 0 0
+       ,status       = Stopped
+       ,mode         = Normal
+       ,minibuffer   = Fast P.empty defaultSty
+       ,uptime       = P.empty
+    }
+
+--
+-- | A global variable holding the state. Todo StateT
+--
+state :: MVar HState
+state = unsafePerformIO $ newMVar emptySt
+{-# NOINLINE state #-}
+
+------------------------------------------------------------------------
+-- state accessor functions
+
+-- | Access a component of the state with a projection function
+getsST :: (HState -> a) -> IO a
+getsST f = withST (return . f)
+
+-- | Perform a (read-only) IO action on the state
+withST :: (HState -> IO a) -> IO a
+withST f = readMVar state >>= f
+
+-- | Modify the state with a pure function
+silentlyModifyST :: (HState -> HState) -> IO ()
+silentlyModifyST  f = modifyMVar_ state (return . f)
+
+------------------------------------------------------------------------
+
+modifyST :: (HState -> HState) -> IO ()
+modifyST f = silentlyModifyST f >> touchST
+
+-- | Modify the state with an IO action, triggering a refresh
+modifySTM :: (HState -> IO HState) -> IO ()
+modifySTM f = modifyMVar_ state f >> touchST
+
+-- | Modify the state with an IO action, returning a value
+modifySTM_ :: (HState -> IO (HState,a)) -> IO a
+modifySTM_ f = modifyMVar state f >>= \a -> touchST >> return a
+
+-- | Trigger a refresh. This is the only way to update the screen
+touchST :: IO ()
+touchST = withMVar state $ \st -> tryPutMVar (modified st) () >> return ()
+
diff --git a/Style.hs b/Style.hs
new file mode 100644
--- /dev/null
+++ b/Style.hs
@@ -0,0 +1,355 @@
+-- 
+-- Copyright (c) 2004-5 Don Stewart - http://www.cse.unsw.edu.au/~dons
+-- 
+-- This program is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation; either version 2 of
+-- the License, or (at your option) any later version.
+-- 
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- General Public License for more details.
+-- 
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+-- 
+
+--
+-- | Color manipulation
+--
+
+module Style where
+
+#include "config.h"
+
+import qualified Curses
+import Data.ByteString (ByteString)
+
+import Data.Char                (toLower)
+import Data.Word                (Word8)
+import Data.Maybe               (fromJust)
+import Data.IORef               (readIORef, writeIORef, newIORef, IORef)
+import qualified Data.Map as M  (fromList, empty, lookup, Map)
+
+import System.IO.Unsafe         (unsafePerformIO)
+import Control.Exception        (handle)
+
+------------------------------------------------------------------------
+
+-- | User-configurable colours
+-- Each component of this structure corresponds to a fg\/bg colour pair
+-- for an item in the ui
+data UIStyle = UIStyle { 
+     window      :: !Style  -- default window colour
+   , helpscreen  :: !Style  -- help screen
+   , titlebar    :: !Style  -- titlebar of window
+   , selected    :: !Style  -- currently playing track
+   , cursors     :: !Style  -- the scrolling cursor line
+   , combined    :: !Style  -- the style to use when the cursor is on the current track
+   , warnings    :: !Style  -- style for warnings
+   , blockcursor :: !Style  -- style for the block cursor when typing text
+   , progress    :: !Style  -- style for the progress bar
+   }
+
+------------------------------------------------------------------------
+
+-- | Colors 
+data Color
+    = RGB {-# UNPACK #-} !Word8 !Word8 !Word8
+    | Default
+    | Reverse
+    deriving (Eq,Ord)
+
+-- | Foreground and background color pairs
+data Style = Style {-# UNPACK #-} !Color !Color 
+    deriving (Eq,Ord)
+
+-- | A list of such values (the representation is optimised)
+data StringA 
+    = Fast   {-# UNPACK #-} !ByteString !Style
+    | FancyS {-# UNPACK #-} ![(ByteString,Style)]  -- one line made up of segments
+
+------------------------------------------------------------------------
+--
+-- | Some simple colours (derivied from proxima\/src\/common\/CommonTypes.hs)
+--
+-- But we don't have a light blue?
+--
+black, grey, darkred, red, darkgreen, green, brown, yellow          :: Color
+darkblue, blue, purple, magenta, darkcyan, cyan, white, brightwhite :: Color
+black       = RGB 0 0 0
+grey        = RGB 128 128 128
+darkred     = RGB 139 0 0
+red         = RGB 255 0 0
+darkgreen   = RGB 0 100 0
+green       = RGB 0 128 0
+brown       = RGB 165 42 42
+yellow      = RGB 255 255 0
+darkblue    = RGB 0 0 139
+blue        = RGB 0 0 255
+purple      = RGB 128 0 128
+magenta     = RGB 255 0 255
+darkcyan    = RGB 0 139 139 
+cyan        = RGB 0 255 255
+white       = RGB 165 165 165
+brightwhite = RGB 255 255 255
+
+defaultfg, defaultbg, reversefg, reversebg :: Color
+#if defined(HAVE_USE_DEFAULT_COLORS)
+defaultfg   = Default
+defaultbg   = Default
+#else
+defaultfg   = white
+defaultbg   = black
+#endif
+reversefg   = Reverse
+reversebg   = Reverse
+
+--
+-- | map strings to colors
+--
+stringToColor :: String -> Maybe Color
+stringToColor s = case map toLower s of
+    "black"         -> Just black
+    "grey"          -> Just grey
+    "darkred"       -> Just darkred
+    "red"           -> Just red
+    "darkgreen"     -> Just darkgreen
+    "green"         -> Just green
+    "brown"         -> Just brown
+    "yellow"        -> Just yellow
+    "darkblue"      -> Just darkblue
+    "blue"          -> Just blue
+    "purple"        -> Just purple
+    "magenta"       -> Just magenta
+    "darkcyan"      -> Just darkcyan
+    "cyan"          -> Just cyan
+    "white"         -> Just white
+    "brightwhite"   -> Just brightwhite
+    "default"       -> Just Default
+    "reverse"       -> Just Reverse
+    _               -> Nothing
+
+------------------------------------------------------------------------
+--
+-- | Set some colours, perform an action, and then reset the colours
+--
+withStyle :: Style -> (IO ()) -> IO ()
+withStyle sty fn = uiAttr sty >>= setAttribute >> fn >> reset
+{-# INLINE withStyle #-}
+
+--
+-- | manipulate the current attributes of the standard screen
+-- Only set attr if it's different to the current one?
+--
+setAttribute :: (Curses.Attr, Curses.Pair) -> IO ()
+setAttribute = uncurry Curses.attrSet
+{-# INLINE setAttribute #-}
+
+--
+-- | Reset the screen to normal values
+--
+reset :: IO ()
+reset = setAttribute (Curses.attr0, Curses.Pair 0)
+{-# INLINE reset #-}
+
+--
+-- | And turn on the colours
+--
+initcolours :: UIStyle -> IO ()
+initcolours sty = do
+    let ls  = [helpscreen sty, warnings sty, window sty, 
+               selected sty, titlebar sty, progress sty,
+               blockcursor sty, cursors sty, combined sty ]
+        (Style fg bg) = progress sty    -- bonus style
+        
+    pairs <- initUiColors (ls ++ [Style bg bg, Style fg fg])
+    writeIORef pairMap pairs
+    -- set the background
+    uiAttr (window sty) >>= \(_,p) -> Curses.bkgrndSet nullA p
+    
+------------------------------------------------------------------------
+--
+-- | Set up the ui attributes, given a ui style record
+--
+-- Returns an association list of pairs for foreground and bg colors,
+-- associated with the terminal color pair that has been defined for
+-- those colors.
+--
+initUiColors :: [Style] -> IO PairMap
+initUiColors stys = do 
+    ls <- sequence [ uncurry fn m | m <- zip stys [1..] ]
+    return (M.fromList ls)
+  where
+    fn :: Style -> Int -> IO (Style, (Curses.Attr,Curses.Pair))
+    fn sty p = do
+        let (CColor (a,fgc),CColor (b,bgc)) = style2curses sty
+        handle (\_ -> return ()) $ Curses.initPair (Curses.Pair p) fgc bgc
+        return (sty, (a `Curses.attrPlus` b, Curses.Pair p))
+
+------------------------------------------------------------------------
+--
+-- | Getting from nice abstract colours to ncurses-settable values
+
+-- 20% of allocss occur here! But there's only 3 or 4 colours :/
+-- Every call to uiAttr
+--
+uiAttr :: Style -> IO (Curses.Attr, Curses.Pair)
+uiAttr sty = do
+    m <- readIORef pairMap
+    return $ lookupPair m sty
+{-# INLINE uiAttr #-}
+
+-- | Given a curses color pair, find the Curses.Pair (i.e. the pair
+-- curses thinks these colors map to) from the state
+lookupPair :: PairMap -> Style -> (Curses.Attr, Curses.Pair)
+lookupPair m s = case M.lookup s m of
+                    Nothing   -> (Curses.attr0, Curses.Pair 0) -- default settings
+                    Just v    -> v
+{-# INLINE lookupPair #-}
+
+-- | Keep a map of nice style defs to underlying curses pairs, created at init time
+type PairMap = M.Map Style (Curses.Attr, Curses.Pair)
+
+-- | map of Curses.Color pairs to ncurses terminal Pair settings
+pairMap :: IORef PairMap
+pairMap = unsafePerformIO $ newIORef M.empty
+{-# NOINLINE pairMap #-}
+
+------------------------------------------------------------------------
+--
+-- Basic (ncurses) colours.
+--
+defaultColor :: Curses.Color
+defaultColor = fromJust $ Curses.color "default"
+
+cblack, cred, cgreen, cyellow, cblue, cmagenta, ccyan, cwhite :: Curses.Color
+cblack     = fromJust $ Curses.color "black"
+cred       = fromJust $ Curses.color "red"
+cgreen     = fromJust $ Curses.color "green"
+cyellow    = fromJust $ Curses.color "yellow"
+cblue      = fromJust $ Curses.color "blue"
+cmagenta   = fromJust $ Curses.color "magenta"
+ccyan      = fromJust $ Curses.color "cyan"
+cwhite     = fromJust $ Curses.color "white"
+
+--
+-- Combine attribute with another attribute
+--
+setBoldA, setReverseA ::  Curses.Attr -> Curses.Attr
+setBoldA     = flip Curses.setBold    True
+setReverseA  = flip Curses.setReverse True
+
+--
+-- | Some attribute constants
+--
+boldA, nullA, reverseA :: Curses.Attr
+nullA       = Curses.attr0
+boldA       = setBoldA      nullA
+reverseA    = setReverseA   nullA
+
+------------------------------------------------------------------------
+
+newtype CColor = CColor (Curses.Attr, Curses.Color)
+-- 
+-- | Map Style rgb rgb colours to ncurses pairs
+-- TODO a generic way to turn an rgb into the nearest curses color
+--
+style2curses :: Style -> (CColor, CColor)
+style2curses (Style fg bg) = (fgCursCol fg, bgCursCol bg)
+{-# INLINE style2curses #-}
+
+fgCursCol :: Color -> CColor
+fgCursCol c = case c of
+    RGB 0 0 0         -> CColor (nullA, cblack)
+    RGB 128 128 128   -> CColor (boldA, cblack)
+    RGB 139 0 0       -> CColor (nullA, cred)
+    RGB 255 0 0       -> CColor (boldA, cred)
+    RGB 0 100 0       -> CColor (nullA, cgreen)
+    RGB 0 128 0       -> CColor (boldA, cgreen)
+    RGB 165 42 42     -> CColor (nullA, cyellow)
+    RGB 255 255 0     -> CColor (boldA, cyellow)
+    RGB 0 0 139       -> CColor (nullA, cblue)
+    RGB 0 0 255       -> CColor (boldA, cblue)
+    RGB 128 0 128     -> CColor (nullA, cmagenta)
+    RGB 255 0 255     -> CColor (boldA, cmagenta)
+    RGB 0 139 139     -> CColor (nullA, ccyan)
+    RGB 0 255 255     -> CColor (boldA, ccyan)
+    RGB 165 165 165   -> CColor (nullA, cwhite)
+    RGB 255 255 255   -> CColor (boldA, cwhite)
+    Default           -> CColor (nullA, defaultColor)
+    Reverse           -> CColor (reverseA, defaultColor)
+    _                 -> CColor (nullA, cblack) -- NB
+
+bgCursCol :: Color -> CColor
+bgCursCol c = case c of
+    RGB 0 0 0         -> CColor (nullA, cblack)
+    RGB 128 128 128   -> CColor (nullA, cblack)
+    RGB 139 0 0       -> CColor (nullA, cred)
+    RGB 255 0 0       -> CColor (nullA, cred)
+    RGB 0 100 0       -> CColor (nullA, cgreen)
+    RGB 0 128 0       -> CColor (nullA, cgreen)
+    RGB 165 42 42     -> CColor (nullA, cyellow)
+    RGB 255 255 0     -> CColor (nullA, cyellow)
+    RGB 0 0 139       -> CColor (nullA, cblue)
+    RGB 0 0 255       -> CColor (nullA, cblue)
+    RGB 128 0 128     -> CColor (nullA, cmagenta)
+    RGB 255 0 255     -> CColor (nullA, cmagenta)
+    RGB 0 139 139     -> CColor (nullA, ccyan)
+    RGB 0 255 255     -> CColor (nullA, ccyan)
+    RGB 165 165 165   -> CColor (nullA, cwhite)
+    RGB 255 255 255   -> CColor (nullA, cwhite)
+    Default           -> CColor (nullA, defaultColor)
+    Reverse           -> CColor (reverseA, defaultColor)
+    _                 -> CColor (nullA, cwhite)    -- NB
+
+defaultSty :: Style
+defaultSty = Style Default Default
+
+------------------------------------------------------------------------
+--
+-- Support for runtime configuration
+-- We choose a simple strategy, read/showable record types, with strings
+-- to represent colors
+--
+-- The fields must map to UIStyle
+--
+-- It is this data type that is stored in 'show' format in ~/.hmp3
+--
+data Config = Config {
+         hmp3_window      :: (String,String)
+       , hmp3_helpscreen  :: (String,String)
+       , hmp3_titlebar    :: (String,String)
+       , hmp3_selected    :: (String,String)
+       , hmp3_cursors     :: (String,String)
+       , hmp3_combined    :: (String,String)
+       , hmp3_warnings    :: (String,String)
+       , hmp3_blockcursor :: (String,String)
+       , hmp3_progress    :: (String,String)
+     } deriving (Show,Read)
+
+--
+-- | Read the ~/.hmp3 file, and construct a UIStyle from it, to insert
+-- into 
+--
+buildStyle :: Config -> UIStyle
+buildStyle bs = UIStyle {
+         window      = f $ hmp3_window      bs
+       , helpscreen  = f $ hmp3_helpscreen  bs
+       , titlebar    = f $ hmp3_titlebar    bs
+       , selected    = f $ hmp3_selected    bs
+       , cursors     = f $ hmp3_cursors     bs
+       , combined    = f $ hmp3_combined    bs
+       , warnings    = f $ hmp3_warnings    bs
+       , blockcursor = f $ hmp3_blockcursor bs
+       , progress    = f $ hmp3_progress    bs
+    }
+
+    where 
+        f (x,y) = Style (g x) (g y)
+        g x     = case stringToColor x of
+                    Nothing -> Default
+                    Just y  -> y
diff --git a/Syntax.hs b/Syntax.hs
new file mode 100644
--- /dev/null
+++ b/Syntax.hs
@@ -0,0 +1,157 @@
+-- 
+-- Copyright (c) 2005 Don Stewart - http://www.cse.unsw.edu.au/~dons
+-- 
+-- This program is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation; either version 2 of
+-- the License, or (at your option) any later version.
+-- 
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- General Public License for more details.
+-- 
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+-- 
+
+--
+-- abstract syntax for mpg123/321 'remote control' commands, so we get
+-- type safe messaging, and parsing of results
+--
+-- See 'README.remote' distributed with mpg321.
+--
+
+module Syntax where
+
+import qualified Data.ByteString.Char8 as P (packAddress,concat,pack,ByteString)
+
+------------------------------------------------------------------------
+--
+-- Values we may print out:
+
+-- Loads and starts playing <file>
+--
+data Load = Load {-# UNPACK #-} !P.ByteString
+
+instance Pretty Load where
+    ppr (Load f) = P.concat [P.packAddress "LOAD "#, f]
+
+-- If '+' or '-' is specified, jumps <frames> frames forward, or backwards,
+-- respectively, in the the mp3 file.  If neither is specifies, jumps to
+-- absolute frame <frames> in the mp3 file.
+data Jump = Jump {-# UNPACK #-} !Int
+
+instance Pretty Jump where
+    ppr (Jump i) = P.concat [P.packAddress "JUMP "#, P.pack . show $ i]
+
+-- Pauses the playback of the mp3 file; if already paused, restarts playback.
+data Pause = Pause
+
+instance Pretty Pause where
+    ppr Pause = P.packAddress "PAUSE"#
+
+-- Quits mpg321.
+data Quit = Quit
+
+instance Pretty Quit where
+    ppr Quit = P.packAddress "QUIT"#
+
+------------------------------------------------------------------------
+--
+-- Values we may have to read back in
+
+-- mpg123 tagline. Output at startup.
+data Tag = Tag
+
+-- Track info if ID fields are in the file, otherwise file name.
+data File = File {-# UNPACK #-} !(Either P.ByteString Id3)
+
+-- ID3 info 
+data Id3 = Id3 
+        { id3title  :: !P.ByteString 
+        , id3artist :: !P.ByteString 
+        , id3album  :: !P.ByteString 
+        , id3str    :: !P.ByteString }   -- cache screen string to draw
+
+--      , year   :: Maybe P.ByteString
+--      , genre  :: Maybe P.ByteString }
+
+
+
+-- Outputs information about the mp3 file after loading.
+-- <a>: version of the mp3 file. Currently always 1.0 with madlib, but don't 
+--      depend on it, particularly if you intend portability to mpg123 as well.
+--      Float/string.
+-- <b>: layer: 1, 2, or 3. Integer.
+-- <c>: Samplerate. Integer.
+-- <d>: Mode string. String.
+-- <e>: Mode extension. Integer.
+-- <f>: Bytes per frame (estimate, particularly if the stream is VBR). Integer.
+-- <g>: Number of channels (1 or 2, usually). Integer.
+-- <h>: Is stream copyrighted? (1 or 0). Integer.
+-- <i>: Is stream CRC protected? (1 or 0). Integer.
+-- <j>: Emphasis. Integer.
+-- <k>: Bitrate, in kbps. (i.e., 128.) Integer.
+-- <l>: Extension. Integer.
+data Info = Info {
+                userinfo      :: !P.ByteString  -- user friendly string
+           --   version       :: !P.ByteString,
+           --   layer         :: !Int,     -- 1,2 or 3
+           --   sampleRate    :: !Int,
+           --   playMode      :: !P.ByteString,
+           --   modeExtns     :: !Int,
+           --   bytesPerFrame :: !Int,
+           --   channelCount  :: !Int,
+           --   copyrighted   :: !Bool,
+           --   checksummed   :: !Bool,
+           --   emphasis      :: !Int,
+           --   bitrate       :: !Int,
+           --   extension     :: !Int 
+            }
+
+-- @F <current-frame> <frames-remaining> <current-time> <time-remaining>
+-- Frame decoding status updates (once per frame).
+-- Current-frame and frames-remaining are integers; current-time and
+-- time-remaining floating point numbers with two decimal places.
+--
+-- Only 1 frame a second is actually read, so make sure it's lazy so
+-- there's no need to evaluate all the others. 
+-- 
+data Frame = Frame {
+                currentFrame   :: Int,
+                framesLeft     :: Int,
+                currentTime    :: (Int,Int),
+                timeLeft       :: (Int,Int)
+             }
+
+-- @P {0, 1, 2}
+-- Stop/pause status.
+-- 0 - playing has stopped. When 'STOP' is entered, or the mp3 file is finished.
+-- 1 - Playing is paused. Enter 'PAUSE' or 'P' to continue.
+-- 2 - Playing has begun again.
+data Status = Stopped
+            | Paused
+            | Playing
+        deriving Eq
+
+data Mode = Normal | Loop | Random deriving (Eq,Bounded,Enum) -- for pred,succ
+
+------------------------------------------------------------------------
+
+--
+-- a pretty printing class
+--
+class Pretty a where
+    ppr :: a -> P.ByteString
+
+--
+-- And a wrapper type 
+--
+data Msg = T {-# UNPACK #-} !Tag
+         | F {-# UNPACK #-} !File
+         | I {-# UNPACK #-} !Info
+         | R {-# UNPACK #-} !Frame
+         | S {-# UNPACK #-} !Status
diff --git a/TODO b/TODO
new file mode 100644
--- /dev/null
+++ b/TODO
@@ -0,0 +1,24 @@
+Todo:
+
+- search should wrap. end point == current line.
+
+- How about having 'i' display information on the file under the cursor?
+  Often file names are not as descriptive, and one might want to see the
+  mp3 tags without playing the song. This requires a binding to libid3.
+
+- Look at how cplay support mpg321 and ogg123
+
+- Add, remove
+
+- queue songs
+
+Possible:
+ - breaks on Solaris and  Irix which lack ncurses.h due to WA_BOLD attrs
+ - Cmd line *files* (not dirs) are not stored in the order they appear on the cmdline
+ - Automated testing, Stress testing
+ - Should random mode not repeat itself?
+ - Dynloaded Config.hs
+ - A simpler, more obviously correct UI.hs, based on a Ppr library
+ - Volume?
+ - An mpd backend? slightly different protocol, but not too different.
+ - We should be able to play oggs
diff --git a/Tree.hs b/Tree.hs
new file mode 100644
--- /dev/null
+++ b/Tree.hs
@@ -0,0 +1,254 @@
+{-# OPTIONS -fno-warn-orphans #-}
+-- 
+-- Copyright (c) 2005 Don Stewart - http://www.cse.unsw.edu.au/~dons
+-- 
+-- This program is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation; either version 2 of
+-- the License, or (at your option) any later version.
+-- 
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- General Public License for more details.
+-- 
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+-- 
+
+--
+-- functions for manipulating file trees
+--
+
+module Tree where
+
+import FastIO
+import Syntax           (Mode(..))
+import Binary           (openBinIO_, Binary(put_, get))
+import qualified Data.ByteString.Char8 as P (drop,map,length,pack,ByteString,joinWithChar)
+
+import Data.Maybe       (catMaybes)
+import Data.Array       (listArray, elems, bounds, Array)
+import Data.Char        (toLower)
+import Data.List        (sortBy,sort,foldl',groupBy)
+
+import System.IO        (IOMode(..),hPutStrLn,stderr,openFile,hClose)
+import System.Directory (Permissions(readable))
+import Control.Exception(handle)
+import Control.Monad    (liftM)
+
+type FilePathP = P.ByteString
+
+-- | A filesystem hierarchy is flattened to just the end nodes
+type DirArray = Array Int Dir
+
+-- | The complete list of .mp3 files
+type FileArray = Array Int File
+
+-- | A directory entry is the directory name, and a list of bound
+-- indicies into the Files array.
+data Dir  =
+    Dir { dname :: !FilePathP        -- ^ directory name
+        , dsize :: !Int              -- ^ number of file entries
+        , dlo   :: !Int              -- ^ index of first entry
+        , dhi   :: !Int }            -- ^ index of last entry
+
+-- Most data is allocated in this structure
+data File =
+    File { fbase :: !FilePathP      -- ^ basename of file
+         , fdir  :: !Int }          -- ^ index of Dir entry 
+
+--
+-- | Given the start directories, populate the dirs and files arrays
+--
+buildTree :: [FilePathP] -> IO (DirArray, FileArray)
+buildTree fs = do
+    (os,dirs) <- partition fs    -- note we will lose the ordering of files given on cmd line.
+
+    let loop xs | seq xs False = undefined -- strictify
+        loop []     = return []
+        loop (a:xs) = do
+            (m,ds) <- expandDir a
+            ms     <- loop $! ds ++ xs  -- add to work list
+            return $! m : ms
+
+    ms' <- liftM catMaybes $! loop dirs
+
+    let extras = merge . doOrphans $ os
+        ms = ms' ++ extras
+
+    let (_,n,dirls,filels) = foldl' make (0,0,[],[]) ms
+        dirsArray = listArray (0,length dirls - 1) (reverse dirls)
+        fileArray = listArray (0, n-1) (reverse filels)
+
+    dirsArray `seq` fileArray `seq` return $ (dirsArray, fileArray)
+
+-- | Create nodes based on dirname for orphan files on cmdline
+doOrphans :: [FilePathP] -> [(FilePathP, [FilePathP])]
+doOrphans []     = []
+doOrphans (f:xs) = (dirnameP f, [basenameP f]) : doOrphans xs
+
+-- | Merge entries with the same root node into a single node
+merge :: [(FilePathP, [FilePathP])] -> [(FilePathP, [FilePathP])]
+merge [] = []
+merge xs =
+    let xs' = sortBy  (\a b -> fst a `compare` fst b) xs
+        xs''= groupBy (\a b -> fst a == fst b) xs'
+    in catMaybes $ map flatten xs''
+  where
+    flatten :: [(FilePathP,[FilePathP])] -> Maybe (FilePathP, [FilePathP])
+    flatten []     = Nothing    -- can't happen
+    flatten (x:ys) = let d = fst x in Just (d, snd x ++ concatMap snd ys)
+
+-- | fold builder, for generating Dirs and Files
+make :: (Int,Int,[Dir],[File]) -> (FilePathP,[FilePathP]) -> (Int,Int,[Dir],[File])
+make (i,n,acc1,acc2) (d,fs) =
+    case listToDir n d fs of
+        (dir,n') -> case map makeFile fs of
+            fs' -> (i+1, n', dir:acc1, (reverse fs') ++ acc2)
+    where
+        makeFile f = File (basenameP f) i
+
+------------------------------------------------------------------------
+
+-- | Expand a single directory into a maybe a  pair of the dir name and any files
+-- Return any extra directories to search in
+--
+-- Assumes no evil sym links
+--
+expandDir :: FilePathP -> IO (Maybe (FilePathP, [FilePathP]),  [FilePathP])
+expandDir f | seq f False = undefined -- stricitfy
+expandDir f = do
+    ls_raw <- Control.Exception.handle (\e -> hPutStrLn stderr (show e) >> return []) $
+                packedGetDirectoryContents f
+    let ls = map (P.joinWithChar '/' f) . sort . filter validFiles $! ls_raw
+    ls `seq` return ()
+    (fs',ds) <- partition ls
+    let fs = filter onlyMp3s fs'
+        v = if null fs then Nothing else Just (f,fs)
+    return (v,ds)
+    where
+          notEdge    p = p /= dot && p /= dotdot
+          validFiles p = notEdge p
+          onlyMp3s   p = mp3 == (P.map toLower . P.drop (P.length p -3) $ p)
+
+          mp3        = P.pack "mp3"
+          dot        = P.pack "."
+          dotdot     = P.pack ".."
+
+--
+-- | Given an the next index into the files array, a directory name, and
+-- a list of files in that dir, build a Dir and return the next index
+-- into the array
+--
+listToDir :: Int -> FilePathP -> [FilePathP] -> (Dir, Int)
+listToDir n d fs =
+        let dir = Dir { dname = packedFileNameEndClean d
+                      , dsize = len
+                      , dlo   = n
+                      , dhi   = n + len - 1 } in (dir, n')
+    where
+        len = length fs
+        n'  = n + len
+
+-- | break a list of file paths into a pair of subliests corresponding
+-- to the paths that point to files and to directories.
+partition :: [FilePathP] -> IO ([FilePathP], [FilePathP])
+partition xs | seq xs False = undefined -- how to make `partition' strict
+partition [] = return ([],[])
+partition (a:xs) = do
+    (fs,ds) <- partition xs
+    x <- doesFileExist a
+    if x then do y <- getPermissions a >>= return . readable
+                 return $! if y then (a:fs, ds) else (fs, ds)
+         else return (fs, a:ds)
+
+------------------------------------------------------------------------
+
+instance Binary a => Binary (Array Int a) where
+    put_ bh arr = do
+        put_ bh (bounds arr)
+        mapM_ (put_ bh) (elems arr)
+    get bh      = do
+        ((x,y) :: (Int,Int)) <- get bh
+        (els   :: [a])       <- sequence $ take (y+1) $ repeat (get bh)
+        return $! listArray (x,y) els
+
+instance Binary File where
+    put_ bh (File nm i) = do
+        put_ bh nm
+        put_ bh i
+    get bh = do
+        nm <- get bh
+        i  <- get bh
+        return (File nm i)
+
+instance Binary Dir where
+    put_ bh (Dir nm sz lo hi) = do
+        put_ bh nm
+        put_ bh sz
+        put_ bh lo
+        put_ bh hi
+    get bh = do
+        nm <- get bh
+        sz <- get bh
+        lo <- get bh
+        hi <- get bh
+        return (Dir nm sz lo hi)
+
+instance Binary Mode where
+    put_ bh = put_ bh . fromEnum
+    get  bh = liftM toEnum $ get bh
+
+-- How we write everything out
+instance Binary SerialT where
+    put_ bh st = do
+        put_ bh (ser_farr st, ser_darr st)
+        put_ bh (ser_indx st)
+        put_ bh (ser_mode st)
+
+    get bh     = do
+        (a,b)<- get bh
+        i    <- get bh
+        m    <- get bh
+        return $ SerialT {
+                    ser_farr = a
+                   ,ser_darr = b
+                   ,ser_indx = i
+                   ,ser_mode = m
+                 }
+
+-----------------------------------------------------------------------
+
+-- | Wrap up the values we're going to dump to disk
+data SerialT = SerialT {
+        ser_farr :: FileArray,
+        ser_darr :: DirArray,
+        ser_indx :: Int,
+        ser_mode :: Mode 
+     }
+
+--
+-- write the arrays out
+--
+writeTree :: FilePath -> SerialT -> IO ()
+writeTree f st = do
+    h    <- openFile   f WriteMode
+    bh   <- openBinIO_ h
+    put_ bh st
+    hClose h
+
+--
+-- | Read the arrays from a file
+-- Read from binMem?
+--
+readTree :: FilePath -> IO SerialT
+readTree f = do
+    h    <- openFile   f ReadMode
+    bh   <- openBinIO_ h        -- openBinMem
+    st   <- get bh
+    hClose h
+    return st
+
diff --git a/UI.hs b/UI.hs
new file mode 100644
--- /dev/null
+++ b/UI.hs
@@ -0,0 +1,715 @@
+{-# OPTIONS -cpp -#include "curses.h" #-}
+
+#if HAVE_SIGNAL_H
+{-#include <signal.h> #-}
+#endif
+
+#include "config.h"
+
+-- 
+-- Copyright (C) 2004-5 Don Stewart - http://www.cse.unsw.edu.au/~dons
+-- 
+-- This program is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation; either version 2 of
+-- the License, or (at your option) any later version.
+-- 
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- General Public License for more details.
+-- 
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+-- 
+-- Derived from: riot/UI.hs
+--      Copyright (c) Tuomo Valkonen 2004.
+--
+-- Released under the same license.
+--
+
+--
+-- | This module defines a user interface implemented using ncurses. 
+--
+--
+
+module UI (
+
+        -- * Construction, destruction
+        start, end, suspend, screenSize, refresh, refreshClock, resetui,
+
+        -- * Input
+        getKey
+
+  )   where
+
+import Style
+import Utils                    (isLightBg)
+import FastIO                   (basenameP, printfPS)
+import Tree                     (File(fdir, fbase), Dir(dname))
+import State
+import Syntax
+import Config
+import qualified Curses
+import {-# SOURCE #-} Keymap    (extraTable, keyTable)
+
+import Data.List                (intersperse,isPrefixOf)
+import Data.Array               ((!), bounds, Array, listArray)
+import Data.Array.Base          (unsafeAt)
+import Control.Monad            (when)
+import qualified Control.Exception (catch, handle)
+import System.IO                (stderr, hFlush)
+import System.Posix.Signals     (raiseSignal, sigTSTP)
+import System.Posix.Env         (getEnv, putEnv)
+
+import qualified Data.ByteString.Char8 as P
+import qualified Data.ByteString       as B
+
+------------------------------------------------------------------------
+
+--
+-- | how to initialise the ui
+--
+start :: IO UIStyle
+start = do
+    Control.Exception.handle (const $ return ()) $ do -- tweak for OpenBSD console
+        thisterm <- getEnv "TERM"
+        case thisterm of 
+            Just "vt220" -> putEnv "TERM=xterm-color"
+            Just t | "xterm" `isPrefixOf` t 
+                   -> silentlyModifyST $ \st -> st { xterm = True }
+            _ -> return ()
+
+    Curses.initCurses resetui
+
+    colorify <- Curses.hasColors
+    light    <- isLightBg
+
+    let sty | colorify && light = lightBgStyle
+            | colorify          = defaultStyle
+            | otherwise         = bwStyle 
+
+    initcolours sty
+    Curses.keypad Curses.stdScr True    -- grab the keyboard
+    nocursor
+
+    return sty
+
+-- | Reset
+resetui :: IO ()
+resetui = resizeui >> nocursor >> refresh
+
+-- | And force invisible
+nocursor :: IO ()
+nocursor = do
+    Control.Exception.catch (Curses.cursSet (fromIntegral (0::Int)) >> return ()) 
+                            (\_ -> return ())
+
+--
+-- | Clean up and go home. Refresh is needed on linux. grr.
+--
+end :: Bool -> IO ()
+end isXterm = do when isXterm $ setXtermTitle [P.pack "xterm"]
+                 Curses.endWin
+
+--
+-- | Suspend the program
+--
+suspend :: IO ()
+suspend = raiseSignal sigTSTP
+
+--
+-- | Find the current screen height and width.
+--
+screenSize :: IO (Int, Int)
+screenSize = Curses.scrSize
+
+--
+-- | Read a key. UIs need to define a method for getting events.
+-- We only need to refresh if we don't have the SIGWINCH signal handler
+-- working for us.
+--
+getKey :: IO Char
+getKey = do
+    k <- Curses.getCh
+#ifdef KEY_RESIZE
+    if k == Curses.keyResize 
+        then do
+# ifndef SIGWINCH
+              redraw >> resizeui >> return ()   -- XXX ^L doesn't work
+# endif
+              getKey
+        else return k
+#else
+    return k
+#endif
+ 
+-- | Resize the window
+-- From "Writing Programs with NCURSES", by Eric S. Raymond and Zeyd M. Ben-Halim
+--
+resizeui :: IO (Int,Int)
+resizeui = do
+    Curses.endWin
+    Curses.resetParams
+    Curses.refresh
+    Curses.scrSize
+
+refresh :: IO ()
+refresh = redraw >> Curses.refresh
+
+refreshClock :: IO ()
+refreshClock = redrawJustClock >> Curses.refresh
+
+------------------------------------------------------------------------
+
+type Pos    = (Int{-H-}, Int{-W-})
+type Size   = (Int{-H-}, Int{-W-})
+
+--
+-- | A class for renderable objects, given the application state, and
+-- for printing the object as a list of strings
+--
+class Element a where
+    draw  :: Size -> Pos -> HState -> Maybe Frame -> a
+
+--
+-- | The elements of the play mode widget
+--
+data PlayScreen = PlayScreen !PPlaying !ProgressBar !PTimes 
+
+-- | How does this all work? Firstly, we mostly want to draw fast strings
+-- directly to the screen. To break the drawing problem down, you need
+-- to write an instance of Element for each element in the ui. Larger
+-- and larger elements then combine these items together. 
+--
+-- Obviously to write the element instance, you need a new type for each
+-- element, to disinguish them. As follows:
+
+newtype PlayList = PlayList [StringA]
+
+newtype PPlaying    = PPlaying    StringA
+newtype PVersion    = PVersion    P.ByteString
+newtype PMode       = PMode       P.ByteString
+newtype PMode2      = PMode2      P.ByteString
+newtype ProgressBar = ProgressBar StringA
+newtype PTimes      = PTimes      StringA
+
+newtype PInfo       = PInfo       P.ByteString
+newtype PId3        = PId3        P.ByteString
+newtype PTime       = PTime       P.ByteString
+
+newtype PlayTitle = PlayTitle StringA
+newtype PlayInfo  = PlayInfo  P.ByteString
+newtype PlayModes = PlayModes P.ByteString
+newtype HelpScreen = HelpScreen [StringA]
+
+------------------------------------------------------------------------
+
+instance Element PlayScreen where
+    draw w x y z = PlayScreen a b c
+        where
+            a = draw w x y z :: PPlaying
+            b = draw w x y z :: ProgressBar
+            c = draw w x y z :: PTimes
+
+-- | Decode the play screen
+printPlayScreen :: PlayScreen -> [StringA]
+printPlayScreen (PlayScreen (PPlaying a) 
+                            (ProgressBar b) 
+                            (PTimes c)) = [a , b , c]
+
+------------------------------------------------------------------------
+
+instance (Element a, Element b) => Element (a,b) where
+    draw a b c d = (draw a b c d, draw a b c d)
+
+------------------------------------------------------------------------
+
+-- Info about the current track
+instance Element PPlaying where
+    draw w@(_,x') x st z = PPlaying . FancyS $ 
+            [(spc2, defaultSty)
+            ,(alignLR (x'-4) a b, defaultSty)]
+        where
+            (PId3 a)  = draw w x st z :: PId3 
+            (PInfo b) = draw w x st z :: PInfo
+
+-- | Id3 Info
+instance Element PId3 where
+    draw _ _ st _ = case id3 st of
+        Just i  -> PId3 $ id3str i
+        Nothing -> PId3 $ case size st of
+                                0 -> emptyVal
+                                _ -> fbase $ (music st) ! (current st)
+
+-- | mp3 information
+instance Element PInfo where
+    draw _ _ st _ = PInfo $ case info st of
+        Nothing  -> emptyVal
+        Just i   -> userinfo i
+
+emptyVal :: P.ByteString
+emptyVal = P.pack "(empty)"
+
+spc2 :: P.ByteString
+spc2 = spaces 2
+
+------------------------------------------------------------------------
+
+instance Element HelpScreen where
+    draw (_,w) _ st _ = HelpScreen $ 
+        [ Fast (f cs h) sty | (h,cs,_) <- keyTable ] ++
+        [ Fast (f cs h) sty | (h,cs) <- extraTable ]
+        where
+            sty  = helpscreen . config $ st
+
+            f :: [Char] -> P.ByteString -> P.ByteString
+            f cs ps = 
+                let p = P.pack str `P.append` ps
+                    s = P.pack (take (tot - P.length p) (repeat ' '))
+                in p `P.append` s
+                where
+                    tot = round $! fromIntegral w *   (0.8::Float)
+                    len = round $! fromIntegral tot * (0.2::Float)
+
+                    -- faststringify
+                    str = take len $ ' ' :
+                            (concat . intersperse " " $ (map pprIt cs)) ++ repeat ' '
+
+                    pprIt c = case c of
+                        k | k == Curses.keyUp    -> "Up"
+                          | k == Curses.keyDown  -> "Down"
+                          | k == Curses.keyPPage -> "PgUp"
+                          | k == Curses.keyNPage -> "PgDn"
+                          | k == Curses.keyLeft  -> "Left"
+                          | k == Curses.keyRight -> "Right"
+                          | k == '\n'            -> "Enter"
+                          | k == '\f'            -> "^L"
+                          | k == Curses.keyEnd   -> "End"
+                          | k == Curses.keyHome  -> "Home"
+                        _ -> show c
+
+------------------------------------------------------------------------
+
+-- | The time used and time left
+instance Element PTimes where
+    draw _ _ _ Nothing       = PTimes $ Fast (spaces 5) defaultSty
+    draw (_,x) _ _ (Just fr) = PTimes $ FancyS $
+                                [(spc2,     defaultSty)
+                                ,(elapsed,  defaultSty)
+                                ,(gap,      defaultSty)
+                                ,(remaining,defaultSty)]
+      where
+        elapsed   = printfPS fmt1 lm lm'
+        remaining = printfPS fmt2 rm rm'
+        fmt1      = P.pack  "%01d:%02d" 
+        fmt2      = P.pack "-%01d:%02d" 
+        (lm,lm')  = quotRem (fst . currentTime $ fr) 60
+        (rm,rm')  = quotRem (fst . timeLeft    $ fr) 60
+        gap       = spaces distance
+        distance  = x - 4 - P.length elapsed - P.length remaining
+
+------------------------------------------------------------------------
+
+-- | A progress bar
+instance Element ProgressBar where
+    draw (_,w) _ st Nothing = ProgressBar . FancyS $
+          [(spc2,defaultSty) ,(spaces (w-4), bgs)]
+        where 
+          (Style _ bg) = progress (config st)
+          bgs          = Style bg bg
+
+    draw (_,w) _ st (Just fr) = ProgressBar . FancyS $
+          [(spc2,defaultSty)
+          ,((spaces distance),fgs)
+          ,((spaces (width - distance)),bgs)]
+        where 
+          width    = w - 4
+          total    = curr + left
+          distance = round ((curr / total) * fromIntegral width)
+          curr     = toFloat (currentTime fr)
+          left     = toFloat (timeLeft fr)
+          (Style fg bg) = progress (config st)
+          bgs           = Style bg bg
+          fgs           = Style fg fg
+
+          toFloat (x,y) | x `seq` y `seq` False = undefined
+          toFloat (x,y) = (fromIntegral x :: Float) + (fromIntegral y / 100)
+
+------------------------------------------------------------------------
+
+-- | Version info
+instance Element PVersion where
+    draw _ _ _ _ = PVersion $ P.pack versinfo
+
+-- | Uptime
+instance Element PTime where
+    draw _ _ st _ = PTime . uptime $ st
+
+-- | Play mode
+instance Element PMode where
+    draw _ _ st _ = PMode $! case status st of 
+                        Stopped -> a
+                        Paused  -> b
+                        Playing -> c
+
+        where a = P.pack "stop"
+              b = P.pack "pause"
+              c = P.pack "play"
+
+-- | Loop, normal or random
+instance Element PMode2 where
+    draw _ _ st _ = PMode2 $ case mode st of 
+                        Random  -> a
+                        Loop    -> b
+                        Normal  -> c
+
+        where a = P.pack "random"
+              b = P.pack "loop"
+              c = P.empty
+
+------------------------------------------------------------------------
+
+instance Element PlayModes where
+    draw a b c d = PlayModes $  
+        m `P.append` if m' == P.empty then P.empty else ' ' `P.cons` m'
+        where
+            (PMode  m ) = draw a b c d :: PMode
+            (PMode2 m') = draw a b c d :: PMode2
+
+instance Element PlayInfo where
+    draw _ _ st _ = PlayInfo $ P.concat
+         [percent
+         ,P.pack " ("
+         ,P.pack (show (1 + ( snd . bounds . folders $ st)))
+         ,P.pack " dir"
+         ,if (snd . bounds $ folders st) == 1 then P.empty else plural
+         ,P.pack ", "
+         ,P.pack (show . size $ st)
+         ,P.pack " file"
+         ,if size st == 1 then P.empty else plural
+         ,P.pack ")"]
+      where
+        plural = P.pack "s"   -- expose to inlining
+        pct    = P.pack "%"
+        curr   = cursor  st
+
+        percent | percent' == 0  && curr == 0 = P.pack "top"
+                | percent' == 100             = P.pack "all"
+                | otherwise = if P.length s == 2 then ' ' `P.cons` s else s
+            where 
+                s = P.pack (show percent') `P.append` pct
+
+                percent' :: Int 
+                percent' = round $ ((fromIntegral curr) / 
+                                   ((fromIntegral . size $ st) - 1) * 100.0 :: Float)
+
+instance Element PlayTitle where
+    draw a@(_,x) b c d =
+        PlayTitle $ flip Fast hl $ P.concat 
+              [space
+              ,inf
+              ,spaces gapl
+              ,modes
+              ,spaces gapr
+              ,time
+              ,space
+              ,ver
+              ,space]
+      where
+        (PlayInfo inf)    = draw a b c d :: PlayInfo
+        (PTime time)      = draw a b c d :: PTime
+        (PlayModes modes) = draw a b c d :: PlayModes
+        (PVersion ver)    = draw a b c d :: PVersion
+
+        gap     = x - padding - P.length inf - modlen - P.length time - P.length ver
+        gapl    = gap `div` 2
+        gapr    = gap - gapl
+        padding = 3
+        modlen  = P.length modes
+        space   = spaces 1
+        hl      = titlebar . config $ c
+
+-- | Playlist
+instance Element PlayList where
+    draw p@(y,x) q@(o,_) st z =
+        PlayList $! title 
+                 : list 
+                 ++ (replicate (height - length list - 2) (Fast P.empty defaultSty))
+                 ++ [minibuffer st]
+        where
+            (PlayTitle title)       = draw p q st z :: PlayTitle
+
+            songs  = music st
+            this   = current st
+            curr   = cursor  st
+            height = y - o
+
+            -- number of screens down, and then offset
+            buflen    = height - 2
+            (screens,select) = quotRem curr buflen -- keep cursor in screen
+
+            playing  = let top = screens * buflen
+                           bot = (screens + 1) * buflen
+                       in if this >= top && this < bot
+                            then this - top -- playing song is visible
+                            else (-1)
+
+            -- visible slice of the playlist
+            visible = slice off (off + buflen) songs
+                where off = screens * buflen
+
+            -- todo: put dir on its own line
+            visible' :: [(Maybe Int, P.ByteString)]
+            visible' = loop (-1) visible
+                where  loop _ []     = []
+                       loop n (v:vs) = 
+                            let r = if fdir v > n then Just (fdir v) else Nothing
+                            in (r,fbase v) : loop (fdir v) vs
+                          
+            -- problem: we color *after* merging with directories
+         -- list   = [ uncurry color n
+         --          | n <- zip (map drawIt visible') [0..] ]
+
+            list   = [ drawIt . color . mchop $ n | n <- zip visible' [0..] ]
+
+            indent = (round $ (0.35 :: Float) * fromIntegral x) :: Int
+                
+            color :: ((Maybe Int,P.ByteString),Int) -> (Maybe Int, StringA)
+            color ((m,s),i) 
+                | i == select && i == playing = f sty3
+                | i == select                 = f sty2
+                | i == playing                = f sty1
+                | otherwise                   = (m,Fast s defaultSty)
+                where
+                    f sty = (m, Fast (s `P.append` 
+                                        (spaces (x-indent-1-P.length s)))
+                                sty)
+            
+            sty1 = selected . config $ st
+            sty2 = cursors  . config $ st
+            sty3 = combined . config $ st
+
+            -- must mchop before drawing.
+            drawIt :: (Maybe Int, StringA) -> StringA
+            drawIt (Nothing,Fast v sty) = 
+                Fast ((spaces (1 + indent)) `P.append` v) sty
+
+            drawIt (Just i,Fast b sty) = FancyS [pref, post]
+              where
+                pref = (d', if sty == sty2 || sty == sty3 then sty2 else sty1)
+                post = (b, sty)
+
+                d   = basenameP $ case size st of
+                                    0 -> P.pack "(empty)"
+                                    _ -> dname $ folders st ! i
+
+                spc = spaces (indent - P.length d)
+
+                d' | P.length d > indent-1 
+                   = P.concat [ P.take (indent+1-4) d 
+                              , (P.init ellipsis) 
+                              , spaces 1 ]
+
+                   | otherwise = P.concat [ d, spaces 1, spc ]
+
+            drawIt _ = error "UI.drawIt: color gaves us a non-Fast StringA!"
+
+            mchop :: ((Maybe Int,P.ByteString),Int) -> ((Maybe Int,P.ByteString),Int) 
+            mchop a@((i,s),j)
+                | P.length s > (x-indent-4-1) 
+                = ((i, P.take (x-indent-4-1) s `P.append` ellipsis),j)
+                | otherwise = a
+
+--
+-- | Decode the list of current tracks
+--
+printPlayList :: PlayList -> [StringA]
+printPlayList (PlayList s) = s
+{-# INLINE printPlayList #-}
+                
+------------------------------------------------------------------------
+
+-- | Take two strings, and pad them in the middle
+alignLR :: Int -> P.ByteString -> P.ByteString -> P.ByteString
+alignLR w l r 
+    | padding >  0 = P.concat [l, gap, r]
+    | otherwise    = P.concat [ P.take (w - P.length r - 4 - 1) l, ellipsis, spaces 1, r]
+
+    where padding = w - P.length l - P.length r
+          gap     = spaces padding
+
+-- | Calculate whitespaces, very common, so precompute likely values
+spaces :: Int -> P.ByteString
+spaces n
+    | n > 100   = P.replicate n ' ' -- unlikely
+    | otherwise = arr ! n
+  where
+    arr :: Array Int P.ByteString   -- precompute some whitespace strs
+    arr = listArray (0,100) [ P.take i s100 | i <- [0..100] ]
+
+    s100 :: P.ByteString
+    s100 = P.replicate 100 ' '  -- seems reasonable
+
+ellipsis :: P.ByteString
+ellipsis = P.pack "... "
+{-# INLINE ellipsis #-}
+
+------------------------------------------------------------------------
+--
+-- | Now write out just the clock line
+-- Speed things up a bit, just use read State.
+--
+redrawJustClock :: IO ()
+redrawJustClock = do 
+   Control.Exception.handle (\_ -> return ()) $ do
+
+   st      <- getsST id
+   let fr = clock st
+   s@(_,w) <- screenSize
+   let (ProgressBar bar) = draw s undefined st fr :: ProgressBar
+       (PTimes times)    = {-# SCC "redrawJustClock.times" #-} draw s undefined st fr :: PTimes
+   Curses.wMove Curses.stdScr 1 0   -- hardcoded!
+   drawLine w bar
+   Curses.wMove Curses.stdScr 2 0   -- hardcoded!
+   drawLine w times
+   drawHelp st fr s
+
+------------------------------------------------------------------------
+--
+-- work for drawing help. draw the help screen if it is up
+--
+drawHelp :: HState -> Maybe Frame -> (Int,Int) -> IO ()
+drawHelp st fr s@(h,w) =
+   when (helpVisible st) $ do
+       let (HelpScreen help') = draw s (0,0) st fr :: HelpScreen
+           (Fast fps _)      = head help'
+           offset            = (w - (P.length fps)) `div` 2
+           height            = (h - length help') `div` 2
+       when (height > 0) $ do
+            Curses.wMove Curses.stdScr ((h - length help') `div` 2) offset
+            mapM_ (\t -> do drawLine w t
+                            (y',_) <- Curses.getYX Curses.stdScr
+                            Curses.wMove Curses.stdScr (y'+1) offset) help'
+
+------------------------------------------------------------------------
+--
+-- | Draw the screen
+--
+redraw :: IO ()
+redraw = 
+   -- linux ncurses, in particular, seems to complain a lot. this is an easy solution
+   Control.Exception.handle (\_ -> return ()) $ do
+
+   s <- getsST id    -- another refresh could be triggered?
+   let f = clock s
+   sz@(h,w) <- screenSize
+
+   let x = printPlayScreen (draw sz (0,0) s f :: PlayScreen)
+       y = printPlayList   (draw sz (length x,0) s f :: PlayList)
+       a = x ++ y
+
+   when (xterm s) $ setXterm s sz f
+   
+   gotoTop
+   mapM_ (\t -> do drawLine w t
+                   (y',x') <- Curses.getYX Curses.stdScr
+                   fillLine
+                   maybeLineDown t h y' x' )
+         (take (h-1) (init a))
+   drawHelp s f sz
+
+   -- minibuffer
+   Curses.wMove Curses.stdScr (h-1) 0
+   fillLine 
+   Curses.wMove Curses.stdScr (h-1) 0
+   drawLine (w-1) (last a)
+   when (miniFocused s) $ do -- a fake cursor
+        drawLine 1 (Fast (spaces 1) (blockcursor . config $ s ))
+        -- todo rendering bug here when deleting backwards in minibuffer
+
+------------------------------------------------------------------------
+--
+-- | Draw a coloured (or not) string to the screen
+--
+drawLine :: Int -> StringA -> IO ()
+drawLine _ (Fast ps sty) = drawPackedString ps sty
+drawLine _ (FancyS ls) = loop ls
+    where loop []             = return ()
+          loop ((l,sty):xs)   = drawPackedString l sty >> loop xs
+
+-- worker
+drawPackedString :: P.ByteString -> Style -> IO ()
+drawPackedString ps sty =
+    withStyle sty $ B.useAsCString ps $ \cstr ->
+        Curses.throwIfErr_ msg $
+            Curses.waddnstr Curses.stdScr cstr (fromIntegral . P.length $ ps)
+    where
+        msg = P.packAddress "drawPackedString"#
+
+
+------------------------------------------------------------------------
+
+maybeLineDown :: StringA -> Int -> Int -> Int -> IO ()
+maybeLineDown (Fast s _) h y _ | s == P.empty = lineDown h y
+maybeLineDown _ h y x
+    | x == 0    = return ()     -- already moved down
+    | otherwise = lineDown h y
+
+------------------------------------------------------------------------
+
+lineDown :: Int -> Int -> IO ()
+lineDown h y = Curses.wMove Curses.stdScr (min h (y+1)) 0
+
+--
+-- | Fill to end of line spaces
+--
+fillLine :: IO ()
+fillLine = Control.Exception.catch (Curses.clrToEol) (\_ -> return ()) -- harmless?
+
+--
+-- | move cursor to origin of stdScr.
+--
+gotoTop :: IO ()
+gotoTop = Curses.wMove Curses.stdScr 0 0
+{-# INLINE gotoTop #-}
+
+-- | Take a slice of an array efficiently
+slice :: Int -> Int -> Array Int e -> [e]
+slice i j arr = 
+    let (a,b) = bounds arr
+    in [unsafeAt arr n | n <- [max a i .. min b j] ]
+{-# INLINE slice #-}
+
+------------------------------------------------------------------------
+
+--
+-- | magics for setting xterm titles using ansi escape sequences
+--
+setXtermTitle :: [P.ByteString] -> IO ()
+setXtermTitle strs = do
+    mapM_ (P.hPut stderr) (before : strs ++ [after])
+    hFlush stderr 
+  where
+    before = P.pack "\ESC]0;"
+    after  = P.pack "\007"
+
+------------------------------------------------------------------------
+
+-- set xterm title (should have an instance Element)
+-- Don't need to do this on each refresh...
+setXterm :: HState -> (Int,Int) -> Maybe Frame -> IO ()
+setXterm s sz f = setXtermTitle $ 
+    if status s == Playing
+      then case id3 s of
+            Nothing -> case size s of
+                            0 -> [P.pack "hmp3"]
+                            _ -> [(fbase $ music s ! current s)]
+            Just ti -> id3artist ti :
+                       if P.null (id3title ti) 
+                            then [] 
+                            else [P.pack ": ", id3title ti]
+      else let (PMode pm) = draw sz (0,0) s f :: PMode in [pm]
+
diff --git a/Utils.hs b/Utils.hs
new file mode 100644
--- /dev/null
+++ b/Utils.hs
@@ -0,0 +1,171 @@
+-- 
+-- Copyright (c) 2003-5 Don Stewart - http://www.cse.unsw.edu.au/~dons
+-- 
+-- This program is free software; you can redistribute it and/or
+-- modify it under the terms of the GNU General Public License as
+-- published by the Free Software Foundation; either version 2 of
+-- the License, or (at your option) any later version.
+-- 
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-- General Public License for more details.
+-- 
+-- You should have received a copy of the GNU General Public License
+-- along with this program; if not, write to the Free Software
+-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+-- 02111-1307, USA.
+-- 
+
+-- miscellaneous utilites, including:
+--
+-- The POpen module provides functionality to ``open'' a process by
+-- creating two pipes, forking, and executing a file. *Two pipes* are
+-- created for *bidirectional* communication with the subprocess, unlike
+-- the popen in the library. This is really popen2.
+--
+-- The return value of the popen command is a tuple of Handle for
+-- reading and writing to the subprocess
+--
+-- The inspiration for this code is J Petersen's hslibs/posix/POpen.hs
+--
+
+module Utils where
+
+import FastIO                   (printfPS)
+import qualified Data.ByteString.Base as P (packAddress,ByteString)
+
+import Data.Char                (toLower)
+import System.Time              (diffClockTimes, TimeDiff(tdSec), ClockTime)
+import System.Environment       (getEnv)
+import System.Posix.Types       (Fd(..),ProcessID)
+import System.Process.Internals (ProcessHandle(..))
+import System.Posix.Process     (forkProcess,executeFile)
+import System.Posix.IO          (createPipe,stdInput,stdError
+                                ,stdOutput,closeFd,dupTo)
+
+import qualified Control.Exception (handle)
+
+------------------------------------------------------------------------
+
+--
+-- | join two path components
+--
+infixr 6 </>
+infixr 6 <+>
+
+(</>), (<+>) :: FilePath -> FilePath -> FilePath
+[] </> b = b
+a  </> b = a ++ "/" ++ b
+
+[] <+> b = b
+a  <+> b = a ++ " " ++ b
+
+------------------------------------------------------------------------
+
+drawUptime :: ClockTime -> ClockTime -> P.ByteString
+drawUptime before now =
+    let r      = diffClockTimes now before
+        s      = tdSec  r
+        (h,sr) = quotRem s (60 * 60)
+        m      = quot sr 60
+    in printfPS fmt h m
+  where
+    fmt = P.packAddress "%3d:%02d"# -- sometimes ghc doesn't want to fire a RULE here, why?
+                                    -- its crucial for snprintf that this is unpacked
+        
+------------------------------------------------------------------------
+-- | Repeat an action
+-- Also known as `forever' in the Awkward squad paper
+repeatM_ :: Monad m => m a -> m ()
+repeatM_ a = a >> repeatM_ a
+{-# SPECIALIZE repeatM_ :: IO a -> IO () #-}
+{-# INLINE repeatM_ #-}
+
+------------------------------------------------------------------------
+
+-- | Convert a (newtyped) Posix Fd to an Int we can use in other places
+fdToInt :: Fd -> Int
+fdToInt (Fd cint) = fromIntegral cint
+
+-- | Wrap a CPid as a System.Process.ProcessHandle
+pid2phdl :: ProcessID -> ProcessHandle
+pid2phdl pid = (ProcessHandle pid)
+{-# NOINLINE pid2phdl #-}
+
+------------------------------------------------------------------------
+--
+-- provide similar functionality to popen(3), 
+-- along with bidirectional ipc via pipes
+-- return's the pid of the child process
+--
+-- there are two different forkProcess functions. the pre-620 was a
+-- unix-fork style function, and the modern function has semantics more
+-- like the Awkward-Squad paper. We provide implementations of popen
+-- using both versions, depending on which GHC the user wants to try.
+--
+-- And now a third, we return stderr.
+-- 
+popen :: FilePath -> [String] -> IO (Fd, Fd, Fd, ProcessID)
+popen cmd args = do
+        (pr, pw)   <- createPipe
+        (cr, cw)   <- createPipe    
+        (cre, cwe) <- createPipe    
+
+        -- parent --
+        let parent = do closeFd cw
+                        closeFd cwe
+                        closeFd pr
+        -- child --
+        let child  = do closeFd pw
+                        closeFd cr 
+                        closeFd cre
+                        exec cmd args (pr,cw,cwe)
+                        error "exec cmd failed!" -- typing only
+
+#if __GLASGOW_HASKELL__ >= 601
+        pid <- forkProcess child -- fork child
+        parent                   -- and run parent code
+#else
+        p   <- forkProcess
+        pid <- case p of
+                Just pid -> parent >> return pid
+                Nothing  -> child
+#endif
+
+   --   hcr <- fdToHandle cr
+   --   hpw <- fdToHandle pw
+
+        return (cr,pw,cre,pid)
+
+--
+-- execve cmd in the child process, dup'ing the file descriptors passed
+-- as arguments to become the child's stdin and stdout.
+--
+exec :: FilePath -> [String] -> (Fd,Fd,Fd) -> IO ()
+exec cmd args (pr,cw,ce) = do
+        dupTo pr stdInput
+        dupTo cw stdOutput      -- dup stderr too!
+        dupTo ce stdError       -- dup stderr too!
+        executeFile cmd False args Nothing
+
+------------------------------------------------------------------------
+
+--
+-- | Some evil to work out if the background is light, or dark. Assume dark.
+--
+isLightBg :: IO Bool
+isLightBg = Control.Exception.handle (\_ -> return False) $ do
+    e <- getEnv "HMP_HAS_LIGHT_BG"
+    return $ map toLower e == "true"
+
+------------------------------------------------------------------------
+
+-- | 'readM' behaves like read, but catches failure in a monad.
+readM :: (Monad m, Read a) => String -> m a
+readM s = case [x | (x,t) <- {-# SCC "Serial.readM.reads" #-} reads s    -- bad!
+               , ("","")  <- lex t] of
+        [x] -> return x
+        []  -> fail "Serial.readM: no parse"
+        _   -> fail "Serial.readM: ambiguous parse"
+
diff --git a/cbits/config.h.in b/cbits/config.h.in
new file mode 100644
--- /dev/null
+++ b/cbits/config.h.in
@@ -0,0 +1,61 @@
+/* cbits/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `curses' library (-lcurses). */
+#undef HAVE_LIBCURSES
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <regex.h> header file. */
+#undef HAVE_REGEX_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `use_default_colors' function. */
+#undef HAVE_USE_DEFAULT_COLORS
+
+/* Which mp3 decoder to use */
+#undef MPG321
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Current patch count */
+#undef PATCH_COUNT
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
diff --git a/cbits/utils.c b/cbits/utils.c
new file mode 100644
--- /dev/null
+++ b/cbits/utils.c
@@ -0,0 +1,86 @@
+
+#include "utils.h"
+
+/*
+ * A non-macro version of getyx(3), to make writing a Haskell binding
+ * easier.  Called in Yi/Curses.hsc
+ */
+void nomacro_getyx(WINDOW *win, int *y, int *x) {
+    getyx(win, *y, *x);
+}
+
+/* A non-macro version of COLOR_PAIR(3)
+ */
+int get_color_pair (int pair) {
+    return COLOR_PAIR (pair);
+}
+
+/*
+ * Specialised packed hGetLine. The caller should copy out any string it
+ * is interested in. Additionally, we drop redundant @F packets arriving --
+ * there's too many anyway
+ *
+ * Note that mpg321 (only) provides --skip-printing-frames=N
+ * I guess we could have used that.
+ */
+#define BUFLEN 1024
+
+#define DROPRATE 10
+
+int FRAME_COUNT = 0;    /* we count frame packets, and drop 9/10 of them */
+                        /* setting this to 10 will force the next
+                         * packet to be returned, no matter what */
+
+/* when skipping frames, we want to ensure we don't drop any packets,
+ * for reasonable performance on updates. This trick does that */
+void forcenext(void) {
+    FRAME_COUNT = DROPRATE ;
+}
+
+/* sometimes we write to the wrong spot after a refresh */
+int getline(char *buf, FILE *hdl) { 
+    char *p;
+    int c;
+
+    /* read first two bytes of packet, to work out if we drop it */
+    getc(hdl);      /* should be '@' */
+    c = getc(hdl);
+
+    /* drop packet */
+    if (c == 'F' && FRAME_COUNT < DROPRATE ) {
+        FRAME_COUNT++;
+
+        while (c != '\n') 
+            c = getc(hdl);
+        return getline(buf,hdl);        /* read another line */
+
+    /* normal packet */
+    } else {
+        if (c == 'F') FRAME_COUNT = 0;    /* reset frame count */
+
+        p = fgets(buf+1, BUFLEN-1, hdl);  /* read rest of line */
+        if (p == NULL) {
+        //  perror("getline failed\n");
+            return (-1);
+        }
+        buf[0] = c;         /* drop the '@' */
+        return strlen(buf); /* return length so we can realloc */
+    }
+}
+            
+/* given a file descriptor (presumably got from a Haskell Handle) , open
+ * a FILE * stream onto that fd. Don't try to use the Handle after this 
+ *
+ * could be done in Haskell...
+ */
+FILE *openfd(int fd) {
+    FILE *file = NULL;
+
+    if ((file = fdopen(fd, "r")) != NULL) {
+         return file;
+    } else {
+         perror("cbits.openfd failed\n\n");
+         close(fd);
+         return NULL;
+    }
+}
diff --git a/cbits/utils.h b/cbits/utils.h
new file mode 100644
--- /dev/null
+++ b/cbits/utils.h
@@ -0,0 +1,16 @@
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <curses.h>
+
+#include "config.h"
+
+/* curses */
+extern void nomacro_getyx(WINDOW *win, int *y, int *x);
+extern int get_color_pair (int pair);
+
+/* packed string IO */
+FILE *openfd(int fd);
+int getline(char *buf, FILE *hdl);
+void forcenext(void);
diff --git a/configure b/configure
new file mode 100644
--- /dev/null
+++ b/configure
@@ -0,0 +1,3916 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.59.
+#
+# Copyright (C) 2003 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+  set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)$' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+  	  /^X\/\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\/\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2"  || {
+  # Find who we are.  Look in the path if we contain no path at all
+  # relative or not.
+  case $0 in
+    *[\\/]* ) as_myself=$0 ;;
+    *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+       ;;
+  esac
+  # We did not find ourselves, most probably we were run as `sh COMMAND'
+  # in which case we are not to be found in the path.
+  if test "x$as_myself" = x; then
+    as_myself=$0
+  fi
+  if test ! -f "$as_myself"; then
+    { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+   { (exit 1); exit 1; }; }
+  fi
+  case $CONFIG_SHELL in
+  '')
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for as_base in sh bash ksh sh5; do
+	 case $as_dir in
+	 /*)
+	   if ("$as_dir/$as_base" -c '
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2" ') 2>/dev/null; then
+	     $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+	     $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+	     CONFIG_SHELL=$as_dir/$as_base
+	     export CONFIG_SHELL
+	     exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+	   fi;;
+	 esac
+       done
+done
+;;
+  esac
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line before each line; the second 'sed' does the real
+  # work.  The second script uses 'N' to pair each line-number line
+  # with the numbered line, and appends trailing '-' during
+  # substitution so that $LINENO is not a special case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # second 'sed' script.  Blame Lee E. McMahon for sed's syntax.  :-)
+  sed '=' <$as_myself |
+    sed '
+      N
+      s,$,-,
+      : loop
+      s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+      t loop
+      s,-$,,
+      s,^['$as_cr_digits']*\n,,
+    ' >$as_me.lineno &&
+  chmod +x $as_me.lineno ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensible to this).
+  . ./$as_me.lineno
+  # Exit status is that of the last command.
+  exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+  *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T='	' ;;
+  *c*,*  ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+  *)       ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  # We could just check for DJGPP; but this test a) works b) is more generic
+  # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+  if test -f conf$$.exe; then
+    # Don't use ln at all; we don't have any links
+    as_ln_s='cp -p'
+  else
+    as_ln_s='ln -s'
+  fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" 	$as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_config_libobj_dir=.
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete.  It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="Setup.hs"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+#  include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS MPG321 CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP LIBOBJS LTLIBOBJS'
+ac_subst_files=''
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+ac_prev=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval "$ac_prev=\$ac_option"
+    ac_prev=
+    continue
+  fi
+
+  ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_option in
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+  | --da=*)
+    datadir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+    eval "enable_$ac_feature=no" ;;
+
+  -enable-* | --enable-*)
+    ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+    case $ac_option in
+      *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "enable_$ac_feature='$ac_optarg'" ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst \
+  | --locals | --local | --loca | --loc | --lo)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package| sed 's/-/_/g'`
+    case $ac_option in
+      *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+      *) ac_optarg=yes ;;
+    esac
+    eval "with_$ac_package='$ac_optarg'" ;;
+
+  -without-* | --without-*)
+    ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/-/_/g'`
+    eval "with_$ac_package=no" ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; }
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+   { (exit 1); exit 1; }; }
+    ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+    eval "$ac_envvar='$ac_optarg'"
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  { echo "$as_me: error: missing argument to $ac_option" >&2
+   { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+  eval ac_val=$`echo $ac_var`
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+    *)  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+	      localstatedir libdir includedir oldincludedir infodir mandir
+do
+  eval ac_val=$`echo $ac_var`
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* ) ;;
+    *)  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then its parent.
+  ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$0" : 'X\(//\)[^/]' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r $srcdir/$ac_unique_file; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+  if test "$ac_srcdir_defaulted" = yes; then
+    { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+   { (exit 1); exit 1; }; }
+  else
+    { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+  fi
+fi
+(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
+  { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
+   { (exit 1); exit 1; }; }
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+  cat <<_ACEOF
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+			  [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+			  [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR           user executables [EPREFIX/bin]
+  --sbindir=DIR          system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR       program executables [EPREFIX/libexec]
+  --datadir=DIR          read-only architecture-independent data [PREFIX/share]
+  --sysconfdir=DIR       read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR   modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR    modifiable single-machine data [PREFIX/var]
+  --libdir=DIR           object code libraries [EPREFIX/lib]
+  --includedir=DIR       C header files [PREFIX/include]
+  --oldincludedir=DIR    C header files for non-gcc [/usr/include]
+  --infodir=DIR          info documentation [PREFIX/info]
+  --mandir=DIR           man documentation [PREFIX/man]
+_ACEOF
+
+  cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\_ACEOF
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  CPPFLAGS    C/C++ preprocessor flags, e.g. -I<include dir> if you have
+              headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  ac_popdir=`pwd`
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d $ac_dir || continue
+    ac_builddir=.
+
+if test "$ac_dir" != .; then
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A "../" for each directory in $ac_dir_suffix.
+  ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+  ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+  .)  # No --srcdir option.  We are building in place.
+    ac_srcdir=.
+    if test -z "$ac_top_builddir"; then
+       ac_top_srcdir=.
+    else
+       ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+    fi ;;
+  [\\/]* | ?:[\\/]* )  # Absolute path.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir ;;
+  *) # Relative path.
+    ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+
+# Do not use `cd foo && pwd` to compute absolute paths, because
+# the directories may not exist.
+case `pwd` in
+.) ac_abs_builddir="$ac_dir";;
+*)
+  case "$ac_dir" in
+  .) ac_abs_builddir=`pwd`;;
+  [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
+  *) ac_abs_builddir=`pwd`/"$ac_dir";;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_builddir=${ac_top_builddir}.;;
+*)
+  case ${ac_top_builddir}. in
+  .) ac_abs_top_builddir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
+  *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_srcdir=$ac_srcdir;;
+*)
+  case $ac_srcdir in
+  .) ac_abs_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
+  *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
+  esac;;
+esac
+case $ac_abs_builddir in
+.) ac_abs_top_srcdir=$ac_top_srcdir;;
+*)
+  case $ac_top_srcdir in
+  .) ac_abs_top_srcdir=$ac_abs_builddir;;
+  [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
+  *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
+  esac;;
+esac
+
+    cd $ac_dir
+    # Check for guested configure; otherwise get Cygnus style configure.
+    if test -f $ac_srcdir/configure.gnu; then
+      echo
+      $SHELL $ac_srcdir/configure.gnu  --help=recursive
+    elif test -f $ac_srcdir/configure; then
+      echo
+      $SHELL $ac_srcdir/configure  --help=recursive
+    elif test -f $ac_srcdir/configure.ac ||
+	   test -f $ac_srcdir/configure.in; then
+      echo
+      $ac_configure --help
+    else
+      echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi
+    cd $ac_popdir
+  done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+  cat <<\_ACEOF
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.59.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo               = `(hostinfo) 2>/dev/null               || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_sep=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+      ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+    2)
+      ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+      # Get rid of the leading space.
+      ac_sep=" "
+      ;;
+    esac
+  done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+{
+  (set) 2>&1 |
+    case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+    *ac_space=\ *)
+      sed -n \
+	"s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+      ;;
+    *)
+      sed -n \
+	"s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+      ;;
+    esac;
+}
+    echo
+
+    cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=$`echo $ac_var`
+      echo "$ac_var='"'"'$ac_val'"'"'"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+## ------------- ##
+## Output files. ##
+## ------------- ##
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=$`echo $ac_var`
+	echo "$ac_var='"'"'$ac_val'"'"'"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+      echo
+      sed "/^$/d" confdefs.h | sort
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      echo "$as_me: caught signal $ac_signal"
+    echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core &&
+  rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+     ' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+  if test "x$prefix" != xNONE; then
+    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+  else
+    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+  fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+  if test -r "$ac_site_file"; then
+    { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special
+  # files actually), so we avoid doing that.
+  if test -f "$cache_file"; then
+    { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . $cache_file;;
+      *)                      . ./$cache_file;;
+    esac
+  fi
+else
+  { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+	       sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+  eval ac_new_val="\$ac_env_${ac_var}_value"
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	{ echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	{ echo "$as_me:$LINENO:   former value:  $ac_old_val" >&5
+echo "$as_me:   former value:  $ac_old_val" >&2;}
+	{ echo "$as_me:$LINENO:   current value: $ac_new_val" >&5
+echo "$as_me:   current value: $ac_new_val" >&2;}
+	ac_cache_corrupted=:
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+      ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+          ac_config_headers="$ac_config_headers cbits/config.h"
+
+
+
+# Look for mpg321
+for ac_prog in mpg321 mpg123
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_MPG321+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$MPG321"; then
+  ac_cv_prog_MPG321="$MPG321" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_MPG321="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+MPG321=$ac_cv_prog_MPG321
+if test -n "$MPG321"; then
+  echo "$as_me:$LINENO: result: $MPG321" >&5
+echo "${ECHO_T}$MPG321" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  test -n "$MPG321" && break
+done
+test -n "$MPG321" || MPG321="false"
+
+if test "$MPG321" = "false" ; then
+    { echo "$as_me:$LINENO: WARNING: You need mpg321 or mpg123 installed to run hmp3" >&5
+echo "$as_me: WARNING: You need mpg321 or mpg123 installed to run hmp3" >&2;}
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define MPG321 "$MPG321"
+_ACEOF
+
+
+# Some libs we need
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  CC=$ac_ct_CC
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  CC=$ac_ct_CC
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+  test -n "$ac_ct_CC" && break
+done
+
+  CC=$ac_ct_CC
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+     "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+  (eval $ac_compiler --version </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+  (eval $ac_compiler -v </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+  (eval $ac_compiler -V </dev/null >&5) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+  (eval $ac_link_default) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # Find the output, starting from the most likely.  This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+# b.out is created by i960 compilers.
+for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
+	;;
+    conftest.$ac_ext )
+	# This is the source file.
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+	ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	# FIXME: I believe we export ac_cv_exeext for Libtool,
+	# but it would be cool to find out if it's true.  Does anybody
+	# maintain Libtool? --akim.
+	export ac_cv_exeext
+	break;;
+    * )
+	break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+  if { ac_try='./$ac_file'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+  fi
+fi
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  export ac_cv_exeext
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_compiler_gnu=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std1 is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std1.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX			-qlanglvl=ansi
+# Ultrix and OSF/1	-std1
+# HP-UX 10.20 and later	-Ae
+# HP-UX older versions	-Aa -D_HPUX_SOURCE
+# SVR4			-Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+  x|xno)
+    echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+  *)
+    echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+    CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+# Some people use a C++ compiler to compile C.  Since we use `exit',
+# in C++ we need to declare it.  In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+  choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  for ac_declaration in \
+   '' \
+   'extern "C" void std::exit (int) throw (); using std::exit;' \
+   'extern "C" void std::exit (int); using std::exit;' \
+   'extern "C" void exit (int) throw ();' \
+   'extern "C" void exit (int);' \
+   'void exit (int);'
+do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_declaration
+#include <stdlib.h>
+int
+main ()
+{
+exit (42);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+continue
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_declaration
+int
+main ()
+{
+exit (42);
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+  echo '#ifdef __cplusplus' >>confdefs.h
+  echo $ac_declaration      >>confdefs.h
+  echo '#endif'             >>confdefs.h
+fi
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+echo "$as_me:$LINENO: checking for addnstr in -lcurses" >&5
+echo $ECHO_N "checking for addnstr in -lcurses... $ECHO_C" >&6
+if test "${ac_cv_lib_curses_addnstr+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcurses  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char addnstr ();
+int
+main ()
+{
+addnstr ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_curses_addnstr=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_curses_addnstr=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_curses_addnstr" >&5
+echo "${ECHO_T}$ac_cv_lib_curses_addnstr" >&6
+if test $ac_cv_lib_curses_addnstr = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBCURSES 1
+_ACEOF
+
+  LIBS="-lcurses $LIBS"
+
+fi
+
+
+for ac_func in use_default_colors
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether non-existent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether non-existent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6
+if test "${ac_cv_prog_egrep+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+    then ac_cv_prog_egrep='grep -E'
+    else ac_cv_prog_egrep='egrep'
+    fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5
+echo "${ECHO_T}$ac_cv_prog_egrep" >&6
+ EGREP=$ac_cv_prog_egrep
+
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_header_stdc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then
+  :
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      exit(2);
+  exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+for ac_header in regex.h sys/types.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists.  ##
+## ------------------------------------------ ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+# And now a trick to get the current patch count:
+if test -d "_darcs" ; then
+    PATCH_COUNT_=`darcs changes --xml-output | sed -n '/^<patch/p;/TAG/q' | wc -l | sed 's/ *//g'`
+else
+    PATCH_COUNT_=""
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define PATCH_COUNT "$PATCH_COUNT_"
+_ACEOF
+
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+  (set) 2>&1 |
+    case `(ac_space=' '; set | grep ac_space) 2>&1` in
+    *ac_space=\ *)
+      # `set' does not quote correctly, so add quotes (double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \).
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;;
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n \
+	"s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+      ;;
+    esac;
+} |
+  sed '
+     t clear
+     : clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     : end' >>confcache
+if diff $cache_file confcache >/dev/null 2>&1; then :; else
+  if test -w $cache_file; then
+    test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+    cat confcache >$cache_file
+  else
+    echo "not updating unwritable cache $cache_file"
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[	 ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[	 ]*$//;
+}'
+fi
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_i=`echo "$ac_i" |
+	 sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
+  # 2. Add them.
+  ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+  set -o posix
+fi
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# Work around bugs in pre-3.0 UWIN ksh.
+$as_unset ENV MAIL MAILPATH
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)$' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+  	  /^X\/\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\/\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2"  || {
+  # Find who we are.  Look in the path if we contain no path at all
+  # relative or not.
+  case $0 in
+    *[\\/]* ) as_myself=$0 ;;
+    *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+       ;;
+  esac
+  # We did not find ourselves, most probably we were run as `sh COMMAND'
+  # in which case we are not to be found in the path.
+  if test "x$as_myself" = x; then
+    as_myself=$0
+  fi
+  if test ! -f "$as_myself"; then
+    { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+  case $CONFIG_SHELL in
+  '')
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for as_base in sh bash ksh sh5; do
+	 case $as_dir in
+	 /*)
+	   if ("$as_dir/$as_base" -c '
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x$as_lineno_3"  = "x$as_lineno_2" ') 2>/dev/null; then
+	     $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
+	     $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
+	     CONFIG_SHELL=$as_dir/$as_base
+	     export CONFIG_SHELL
+	     exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+	   fi;;
+	 esac
+       done
+done
+;;
+  esac
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line before each line; the second 'sed' does the real
+  # work.  The second script uses 'N' to pair each line-number line
+  # with the numbered line, and appends trailing '-' during
+  # substitution so that $LINENO is not a special case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # second 'sed' script.  Blame Lee E. McMahon for sed's syntax.  :-)
+  sed '=' <$as_myself |
+    sed '
+      N
+      s,$,-,
+      : loop
+      s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+      t loop
+      s,-$,,
+      s,^['$as_cr_digits']*\n,,
+    ' >$as_me.lineno &&
+  chmod +x $as_me.lineno ||
+    { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensible to this).
+  . ./$as_me.lineno
+  # Exit status is that of the last command.
+  exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+  *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T='	' ;;
+  *c*,*  ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+  *)       ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+  # We could just check for DJGPP; but this test a) works b) is more generic
+  # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+  if test -f conf$$.exe; then
+    # Don't use ln at all; we don't have any links
+    as_ln_s='cp -p'
+  else
+    as_ln_s='ln -s'
+  fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" 	$as_nl"
+
+# CDPATH.
+$as_unset CDPATH
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.  Logging --version etc. is OK.
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.59.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+  echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+  echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+  echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+  echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number, then exit
+  -q, --quiet      do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+  --header=FILE[:TEMPLATE]
+		   instantiate the configuration header FILE
+
+Configuration headers:
+$config_headers
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.59,
+  with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2003 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value.  By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=*)
+    ac_option=`expr "x$1" : 'x\([^=]*\)='`
+    ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  -*)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  *) # This is not an option, so the user has probably given explicit
+     # arguments.
+     ac_option=$1
+     ac_need_defaults=false;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --vers* | -V )
+    echo "$ac_cs_version"; exit 0 ;;
+  --he | --h)
+    # Conflict between --help and --header
+    { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+   { (exit 1); exit 1; }; };;
+  --help | --hel | -h )
+    echo "$ac_cs_usage"; exit 0 ;;
+  --debug | --d* | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+    ac_need_defaults=false;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+   { (exit 1); exit 1; }; } ;;
+
+  *) ac_config_targets="$ac_config_targets $1" ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+if \$ac_cs_recheck; then
+  echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+  exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+
+
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+  case "$ac_config_target" in
+  # Handling of arguments.
+  "cbits/config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS cbits/config.h" ;;
+  *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason to put it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+  trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+  trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./confstat$$-$RANDOM
+  (umask 077 && mkdir $tmp)
+} ||
+{
+   echo "$me: cannot create a temporary directory in ." >&2
+   { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+#
+# CONFIG_HEADER section.
+#
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s,^\([	 ]*\)#\([	 ]*define[	 ][	 ]*\)'
+ac_dB='[	 ].*$,\1#\2'
+ac_dC=' '
+ac_dD=',;t'
+# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_uA='s,^\([	 ]*\)#\([	 ]*\)undef\([	 ][	 ]*\)'
+ac_uB='$,\1#\2define\3'
+ac_uC=' '
+ac_uD=',;t'
+
+for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue
+  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+  case $ac_file in
+  - | *:- | *:-:* ) # input from stdin
+	cat >$tmp/stdin
+	ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+	ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+	ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+  * )   ac_file_in=$ac_file.in ;;
+  esac
+
+  test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+
+  # First look for the input files in the build tree, otherwise in the
+  # src tree.
+  ac_file_inputs=`IFS=:
+    for f in $ac_file_in; do
+      case $f in
+      -) echo $tmp/stdin ;;
+      [\\/$]*)
+	 # Absolute (can't be DOS-style, as IFS=:)
+	 test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+   { (exit 1); exit 1; }; }
+	 # Do quote $f, to prevent DOS paths from being IFS'd.
+	 echo "$f";;
+      *) # Relative
+	 if test -f "$f"; then
+	   # Build tree
+	   echo "$f"
+	 elif test -f "$srcdir/$f"; then
+	   # Source tree
+	   echo "$srcdir/$f"
+	 else
+	   # /dev/null tree
+	   { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+   { (exit 1); exit 1; }; }
+	 fi;;
+      esac
+    done` || { (exit 1); exit 1; }
+  # Remove the trailing spaces.
+  sed 's/[	 ]*$//' $ac_file_inputs >$tmp/in
+
+_ACEOF
+
+# Transform confdefs.h into two sed scripts, `conftest.defines' and
+# `conftest.undefs', that substitutes the proper values into
+# config.h.in to produce config.h.  The first handles `#define'
+# templates, and the second `#undef' templates.
+# And first: Protect against being on the right side of a sed subst in
+# config.status.  Protect against being in an unquoted here document
+# in config.status.
+rm -f conftest.defines conftest.undefs
+# Using a here document instead of a string reduces the quoting nightmare.
+# Putting comments in sed scripts is not portable.
+#
+# `end' is used to avoid that the second main sed command (meant for
+# 0-ary CPP macros) applies to n-ary macro definitions.
+# See the Autoconf documentation for `clear'.
+cat >confdef2sed.sed <<\_ACEOF
+s/[\\&,]/\\&/g
+s,[\\$`],\\&,g
+t clear
+: clear
+s,^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 (][^	 (]*\)\(([^)]*)\)[	 ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp
+t end
+s,^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 ][^	 ]*\)[	 ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp
+: end
+_ACEOF
+# If some macros were called several times there might be several times
+# the same #defines, which is useless.  Nevertheless, we may not want to
+# sort them, since we want the *last* AC-DEFINE to be honored.
+uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines
+sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs
+rm -f confdef2sed.sed
+
+# This sed command replaces #undef with comments.  This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >>conftest.undefs <<\_ACEOF
+s,^[	 ]*#[	 ]*undef[	 ][	 ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */,
+_ACEOF
+
+# Break up conftest.defines because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo '  # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS
+echo '  if grep "^[	 ]*#[	 ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS
+echo '  # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS
+echo '  :' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.defines >/dev/null
+do
+  # Write a limited-size here document to $tmp/defines.sed.
+  echo '  cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS
+  # Speed up: don't consider the non `#define' lines.
+  echo '/^[	 ]*#[	 ]*define/!b' >>$CONFIG_STATUS
+  # Work around the forget-to-reset-the-flag bug.
+  echo 't clr' >>$CONFIG_STATUS
+  echo ': clr' >>$CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS
+  echo 'CEOF
+  sed -f $tmp/defines.sed $tmp/in >$tmp/out
+  rm -f $tmp/in
+  mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail
+  rm -f conftest.defines
+  mv conftest.tail conftest.defines
+done
+rm -f conftest.defines
+echo '  fi # grep' >>$CONFIG_STATUS
+echo >>$CONFIG_STATUS
+
+# Break up conftest.undefs because some shells have a limit on the size
+# of here documents, and old seds have small limits too (100 cmds).
+echo '  # Handle all the #undef templates' >>$CONFIG_STATUS
+rm -f conftest.tail
+while grep . conftest.undefs >/dev/null
+do
+  # Write a limited-size here document to $tmp/undefs.sed.
+  echo '  cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS
+  # Speed up: don't consider the non `#undef'
+  echo '/^[	 ]*#[	 ]*undef/!b' >>$CONFIG_STATUS
+  # Work around the forget-to-reset-the-flag bug.
+  echo 't clr' >>$CONFIG_STATUS
+  echo ': clr' >>$CONFIG_STATUS
+  sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS
+  echo 'CEOF
+  sed -f $tmp/undefs.sed $tmp/in >$tmp/out
+  rm -f $tmp/in
+  mv $tmp/out $tmp/in
+' >>$CONFIG_STATUS
+  sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail
+  rm -f conftest.undefs
+  mv conftest.tail conftest.undefs
+done
+rm -f conftest.undefs
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+  # Let's still pretend it is `configure' which instantiates (i.e., don't
+  # use $as_me), people would be surprised to read:
+  #    /* config.h.  Generated by config.status.  */
+  if test x"$ac_file" = x-; then
+    echo "/* Generated by configure.  */" >$tmp/config.h
+  else
+    echo "/* $ac_file.  Generated by configure.  */" >$tmp/config.h
+  fi
+  cat $tmp/in >>$tmp/config.h
+  rm -f $tmp/in
+  if test x"$ac_file" != x-; then
+    if diff $ac_file $tmp/config.h >/dev/null 2>&1; then
+      { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+      { if $as_mkdir_p; then
+    mkdir -p "$ac_dir"
+  else
+    as_dir="$ac_dir"
+    as_dirs=
+    while test ! -d "$as_dir"; do
+      as_dirs="$as_dir $as_dirs"
+      as_dir=`(dirname "$as_dir") 2>/dev/null ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| \
+	 .     : '\(.\)' 2>/dev/null ||
+echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+  	  /^X\(\/\/\)$/{ s//\1/; q; }
+  	  /^X\(\/\).*/{ s//\1/; q; }
+  	  s/.*/./; q'`
+    done
+    test ! -n "$as_dirs" || mkdir $as_dirs
+  fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
+   { (exit 1); exit 1; }; }; }
+
+      rm -f $ac_file
+      mv $tmp/config.h $ac_file
+    fi
+  else
+    cat $tmp/config.h
+    rm -f $tmp/config.h
+  fi
+done
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || { (exit 1); exit 1; }
+fi
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,26 @@
+
+AC_INIT(Setup.hs)
+AC_CONFIG_HEADERS([cbits/config.h])
+AC_PREREQ([2.52])
+
+# Look for mpg321
+AC_CHECK_PROGS(MPG321, [mpg321 mpg123], [false])
+if test "$MPG321" = "false" ; then
+    AC_MSG_WARN([You need mpg321 or mpg123 installed to run hmp3])
+fi
+AC_DEFINE_UNQUOTED(MPG321, "$MPG321", [Which mp3 decoder to use])
+
+# Some libs we need
+AC_CHECK_LIB(curses,  addnstr)
+AC_CHECK_FUNCS(use_default_colors)
+AC_CHECK_HEADERS([regex.h sys/types.h])
+
+# And now a trick to get the current patch count:
+if test -d "_darcs" ; then
+    PATCH_COUNT_=`darcs changes --xml-output | sed -n '/^<patch/p;/TAG/q' | wc -l | sed 's/ *//g'`
+else
+    PATCH_COUNT_=""
+fi
+AC_DEFINE_UNQUOTED(PATCH_COUNT, "$PATCH_COUNT_", [Current patch count])
+
+AC_OUTPUT
diff --git a/hmp3.cabal b/hmp3.cabal
new file mode 100644
--- /dev/null
+++ b/hmp3.cabal
@@ -0,0 +1,20 @@
+Name:                hmp3
+Version:             1.1
+License:             GPL
+License-file:        LICENSE
+Author:              Don Stewart
+Maintainer:          dons@cse.unsw.edu.au
+Build-Depends:       base, unix, fps>=0.7
+
+Executable:          hmp3
+Main-is:             Main.hs
+extensions:          CPP, ForeignFunctionInterface
+extra-libraries:     curses
+include-dirs:        cbits
+c-sources:           cbits/utils.c
+other-modules:       Curses Regex
+ghc-options:         -Wall -fglasgow-exts -O2 -funbox-strict-fields -fasm -optl-Wl,-s -Icbits -threaded
+ 
+-- ghc-options:         -Wall -fglasgow-exts -O2 -funbox-strict-fields -fvia-C -optc-O3 -optl-Wl,-s -Icbits -threaded -lncurses
+-- ghc-options:         -prof -auto-all -Wall -fglasgow-exts -O2 -optc-O3 -funbox-strict-fields -Icbits -threaded -lncurses
+-- ghc-options:         -Wall -fglasgow-exts -Onot -Icbits -threaded -lncurses
