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 +203/−0
- Config.hs +86/−0
- Core.hs +570/−0
- Curses.hsc +638/−0
- FastIO.hs +221/−0
- Keymap.hs +212/−0
- Keymap.hs-boot +8/−0
- LICENSE +340/−0
- Lexer.hs +163/−0
- Lexers.hs +552/−0
- Main.hs +105/−0
- README +97/−0
- Regex.hsc +133/−0
- Setup.hs +3/−0
- State.hs +162/−0
- Style.hs +355/−0
- Syntax.hs +157/−0
- TODO +24/−0
- Tree.hs +254/−0
- UI.hs +715/−0
- Utils.hs +171/−0
- cbits/config.h.in +61/−0
- cbits/utils.c +86/−0
- cbits/utils.h +16/−0
- configure +3916/−0
- configure.ac +26/−0
- hmp3.cabal +20/−0
+ 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 ®free"+ 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