packages feed

hmp3 (empty) → 1.1

raw patch · 27 files changed

+9294/−0 lines, 27 filesdep +basedep +fpsdep +unixbuild-type:Customsetup-changed

Dependencies added: base, fps, unix

Files

+ Binary.hs view
@@ -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', () #) }
+ Config.hs view
@@ -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"
+ Core.hs view
@@ -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)
+ Curses.hsc view
@@ -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+
+ FastIO.hs view
@@ -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
+ Keymap.hs view
@@ -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 ]
+ Keymap.hs-boot view
@@ -0,0 +1,8 @@+module Keymap where++import Data.ByteString++keymap :: [Char] -> [IO ()]++keyTable   :: [(ByteString, [Char], IO ())]+extraTable :: [(ByteString, [Char])]
+ LICENSE view
@@ -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.
+ Lexer.hs view
@@ -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))+
+ Lexers.hs view
@@ -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  = ($[])
+ Main.hs view
@@ -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+
+ README view
@@ -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
+ Regex.hsc view
@@ -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+
+ Setup.hs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+import Distribution.Simple+main = defaultMainWithHooks defaultUserHooks
+ State.hs view
@@ -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 ()+
+ Style.hs view
@@ -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
+ Syntax.hs view
@@ -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
+ TODO view
@@ -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
+ Tree.hs view
@@ -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+
+ UI.hs view
@@ -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]+
+ Utils.hs view
@@ -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"+
+ cbits/config.h.in view
@@ -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
+ cbits/utils.c view
@@ -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;+    }+}
+ cbits/utils.h view
@@ -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);
+ configure view
@@ -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+
+ configure.ac view
@@ -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
+ hmp3.cabal view
@@ -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