packages feed

gcodehs-0.1.1.0: app/Main.hs

{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where

import Data.GCode

import Prelude hiding (readFile, putStrLn)

import Control.Applicative

import Pipes
import Pipes.Attoparsec as PA
import qualified Pipes.Prelude as P
import qualified Pipes.ByteString as B
--import Pipes.ByteString.MMap
import Pipes.Safe
import qualified System.IO as IO

import Data.Monoid ((<>))
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy as BL

import Options.Applicative
import Options.Applicative.Builder

data Flags = Flags {
    input :: FilePath
  , output :: FilePath
  , pretty :: Bool
  , analyze :: Bool
  } deriving (Show)

-- switch to arguments when following is fixed and tab-completion
-- prefers arguments before options
-- https://github.com/pcapriotti/optparse-applicative/issues/173
--  <$> argument str (metavar "FILE")

flags :: Parser Flags
flags = Flags
    <$> strOption ( long "input" <> short 'i' <> metavar "INPUT")
    <*> strOption ( long "output" <> short 'o' <> metavar "OUTPUT" <> value "")
    <*> switch ( long "pretty" <> short 'p' <> help "Pretty output")
    <*> switch ( long "analyze" <> short 'a' <> help "Analyze GCode")

main =
    execParser opts >>= run
    where
      opts = info (helper <*> flags)
        ( fullDesc
       <> progDesc "Process GCode from INPUT"
       <> header "gcodehs - GCode processor" )

run :: Flags -> IO ()
run Flags{..} =
    if analyze
        then do
            r <- foldedpipe input analyzefold
            print r
        else case output of
              "" -> gcodepipe input $ fmt pretty >-> B.stdout
              _  -> IO.withFile output IO.WriteMode $ \outhandle ->
                      gcodepipe input $ fmt pretty >-> B.toHandle outhandle

bufsize = 1024

parseProducer handle = PA.parsed parseGCodeLine (B.hGetSome bufsize handle)

gcodepipe filepath tail =
  IO.withFile filepath IO.ReadMode $ \handle ->
    runSafeT . runEffect $
      (() <$  parseProducer handle)
      >-> tail

foldedpipe filepath fold =
  IO.withFile filepath IO.ReadMode $ \handle ->
      runSafeT . runEffect $
        fold (() <$  parseProducer handle)

analyzefold = P.fold step 0 id
  where step x a = x + 1 -- travel a

--analyzefold' = P.fold step 0 id
--  where step x a | isG a = x + 1
--        step x a | otherwise = x

fmt True  = P.map ppGCodeLine >-> P.map (BS.pack . (++"\n"))
fmt False = P.map ppGCodeLineCompact >-> P.map (BS.pack . (++"\n"))

-- mmaped version, requires pipes-bytestring-mmap
--main' = do
--  file    <- fmap Prelude.head getArgs
--  runSafeT . runEffect $
--    (() <$ PA.parsed parseGCodeLine (unsafeMMapFile file) )
--    >-> P.map ppGCodeLine
--    >-> P.stdoutLn