{-# OPTIONS_GHC -XPatternSignatures -XBangPatterns #-} module Main where import System.IO import System.Process import System.Directory import System.Environment import Text.ParserCombinators.Parsec import Text.Printf import Data.Maybe import Control.Monad import Control.Monad.State import Control.Concurrent import Control.Exception( evaluate ) import Debug.Trace import Data.Time import Control.Parallel.Strategies type Pool = Chan () data CharOrColor = Ch !Char | St !(Style -> Style) instance Show CharOrColor where show (Ch x) = [x] show (St t) = show (t emptyStyle) type CCode = (Int,Int,Int) data Style = Style { fgcol :: !CCode, bgcol :: !CCode, bbold :: !Bool, uline :: !Bool, flash :: !Bool, inverse :: !Bool } deriving (Show) beginSpan :: Style -> String beginSpan !style = let format = "" in let (!r1,!g1,!b1) :: CCode = if inverse style then bgcol style else fgcol style in let (!r2,!g2,!b2) :: CCode = if inverse style then fgcol style else bgcol style in let bold :: String = if bbold style then "bold" else "normal" in let underline :: String = if uline style then "; text-decoration: underline" else "" in let flashy :: String = if flash style then "; text-decoration: blink" else "" in printf format r1 g1 b1 r2 g2 b2 bold underline flashy {- Printf version is clearer, but slower beginSpan :: Style -> String beginSpan !style = let format = "" in let col1 :: CCode = if inverse style then bgcol style else fgcol style in let col2 :: CCode = if inverse style then fgcol style else bgcol style in let bold :: String = if bbold style then "bold" else "normal" in let underline :: String = if uline style then "; text-decoration: underline" else "" in let flashy :: String = if flash style then "; text-decoration: blink" else "" in "" -} formatCol :: CCode -> String formatCol (!r,!g,!b) = printf "#%02x%02x%02x" r g b emptyStyle = Style { fgcol = white, bgcol = black, bbold = False, uline = False, inverse = False, flash = False } red = (251,35,23) :: CCode green = (24,251,24) :: CCode yellow = (220,200,24) :: CCode blue = (34,24,251) :: CCode magenta = (197,0,255) :: CCode cyan = (83,255,255) :: CCode white = (255,255,255) :: CCode grey = (100,100,100) :: CCode black = (0,0,0) :: CCode light :: CCode -> CCode light (!r,!g,!b) = (min (r+100) 255, min (g+100) 255, min (b+100) 255 ) colorParser = do char '\ESC' char '[' code0 <|> code1 <|> code4 <|> code5 <|> code7 code0 = do char '0' clear <|> code0' code1 = do char '1' bold <|> code1' code0' = do char ';' mod <- parseMod col <- justColor char 'm' return $ St (mod col) code1' = do char ';' mod <- parseMod col <- justColor char 'm' return $ St (mod (light col)) parseMod = fgcolP <|> bgcolP where fgcolP = char '3' >> return (\y x -> x { fgcol = y } ) bgcolP = char '4' >> return (\y x -> x { bgcol = y } ) justColor = pGrey <|> pRed <|> pGreen <|> pYellow <|> pBlue <|> pMagenta <|> pCyan <|> pWhite where pGrey = char '0' >> return grey pRed = char '1' >> return red pGreen = char '2' >> return green pYellow = char '3' >> return yellow pBlue = char '4' >> return blue pMagenta = char '5' >> return magenta pCyan = char '6' >> return cyan pWhite = char '7' >> return white -- clear = do char 'm' return $ St (\_ -> emptyStyle) bold = do char 'm' return $ St (\ x -> x{ bbold = True } ) code4 = do string "4m" return $ St (\ x -> x{ uline = True } ) code5 = do string "7m" return $ St (\ x -> x{ flash = True } ) code7 = do string "5m" return $ St (\ x -> x{ inverse = True } ) dataParser :: Parser CharOrColor dataParser = try colorParser <|> (anyChar >>= (\x -> return (Ch x))) mainParser :: Parser [CharOrColor] mainParser = many dataParser {- Replaced by state monad version hPrintHtml :: Handle -> Style -> CharOrColor -> IO Style hPrintHtml hnd state (Ch '\n') = do hPutStrLn hnd "
" return state hPrintHtml hnd state (Ch ' ') = do hPutStr hnd " " return state hPrintHtml hnd state (Ch '<') = do hPutStr hnd "<" return state hPrintHtml hnd state (Ch '>') = do hPutStr hnd ">" return state hPrintHtml hnd state (Ch x) = do hPutStr hnd [x] return state hPrintHtml hnd state (St st) = do hPutStr hnd "
" hPutStr hnd (beginSpan (st state)) return (st state) -} hPrintHtml :: CharOrColor -> StateT (Handle,Style) IO () hPrintHtml (Ch '\n') = do (hnd,_) <- get liftIO $ hPutStrLn hnd "
" hPrintHtml (Ch ' ') = do (hnd,_) <- get liftIO $ hPutStr hnd " " hPrintHtml (Ch '<') = do (hnd,_) <- get liftIO $ hPutStr hnd "<" hPrintHtml (Ch '>') = do (hnd,_) <- get liftIO $ hPutStr hnd ">" hPrintHtml (Ch x) = do (hnd,_) <- get liftIO $ hPutChar hnd x hPrintHtml (St st) = do (hnd,style) <- get put (hnd,st style) (_,style2) <- get liftIO $ hPutStr hnd $ "
" ++ (beginSpan $ style2) split :: (Eq a) => a -> [a] -> [[a]] split c str = let (p,ps) = aux str in (p:ps) where aux [] = ([],[]) aux (x:cs) = let (xs,xss) = aux cs in if x == c then ([c],(xs:xss)) else ((x:xs),xss) splitPred :: (Eq a) => (a -> Bool) -> [a] -> [[a]] splitPred pr str = let (p,ps) = aux str in (p:ps) where aux [] = ([],[]) aux (x:cs) = let (xs,xss) = aux cs in if pr x then ([],((x:xs):xss)) else ((x:xs),xss) {- split :: (Eq a) => a -> [a] -> [[a]] split c str = aux [] str where aux acc [] = [acc] aux acc (x:xs) = if x == c then (acc++[x]) : (aux [] xs) else aux (acc++[x]) xs -} {- splitPred :: (Eq a) => (a -> Bool) -> [a] -> [[a]] splitPred pred str = aux [] str where aux acc [] = [acc] aux acc (x:xs) = if pred x then acc : (aux [x] xs) else aux (acc++[x]) xs -} doOneFile :: String -> IO () doOneFile fname = do t1 <- getCurrentTime doesFileExist (fname ++ ".html") >>= \b -> if b then hPutStrLn stderr $ printf "File already processed, skipping: %s" fname else do src <- readFile fname out <- openFile (fname ++ ".html") WriteMode hSetBuffering out (BlockBuffering (Just 64000)) hPutStrLn out "" hPutStrLn out "" hPutStrLn out "" hPutStrLn out "" let extractData = \p -> case p of Right x -> x Left err -> (trace . show $ err) [] let srcSplit = splitPred (`elem`"\n") src let parsed = concatMap (extractData . parse mainParser fname) srcSplit execStateT (hPrintHtml (St id)) (out,emptyStyle) -- wypisujemy pierwszy wiersz execStateT (mapM_ hPrintHtml parsed) (out,emptyStyle) hPutStrLn out "" hPutStrLn out "" hPutStrLn out "" t2 <- getCurrentTime hPutStrLn stderr $ printf "File %s processed. It took %s. File size was %d characters." fname (show $ diffUTCTime t2 t1) (length src) hClose out {- thread pool stuff -} takeFromPool :: Pool -> IO () takeFromPool p = readChan p >> return () fillPool :: Pool -> IO () fillPool p = writeChan p () makeThreadPool :: Int -> IO Pool makeThreadPool num = do p <- newChan repeatNum num (fillPool p) return p repeatNum :: Int -> IO () -> IO () repeatNum n act | n > 0 = act >> (repeatNum (n-1) act) | otherwise = return () {- end thread pool stuff -} sparkComp :: Pool -> IO () -> IO (MVar ()) sparkComp pool comp = do takeFromPool pool mvar <- newEmptyMVar forkIO $ (comp >> fillPool pool >> putMVar mvar ()) -- core dumped once, when changed do forkOS and run with -N2 return mvar mapMPar :: (a -> IO ()) -> [a] -> Int -> IO () mapMPar comp lst numT = do tPool <- makeThreadPool numT mvars <- mapM (sparkComp tPool) (map comp lst) mapM_ takeMVar (mvars :: [MVar ()]) return () numThreads = 1 {- -} mapMPar' :: (a -> IO ()) -> [a] -> IO () mapMPar' comp lst = mapM_ (\a -> sparkComp' (comp a)) lst sparkComp' :: IO a -> IO () sparkComp' comp = do mvar <- newEmptyMVar forkIO $ (comp >> putMVar mvar ()) takeMVar mvar {- -} main :: IO () main = do args <- getArgs pn <- getProgName -- if args == [] then runCommand (pn ++ " *.log") >>= waitForProcess >> return () else mapM_ doOneFile args mapM_ doOneFile args -- mapMPar doOneFile args numThreads -- mapMPar' doOneFile args return ()