packages feed

splitter-0.1.0.0: Main.hs

module Main (main) where

{-
 - This is a remake of 'tee' written in Haskell for the Cross Platform benefits.
 -}

import Control.Monad

import Data.List (intercalate)

import System.IO
import System.Environment ( getArgs )
import System.Exit
import System.Console.GetOpt
import System.FilePath
import System.Directory

import Text.Parsec.Error

import Data.Range.Range
import Data.Range.Parser

main :: IO ()
main = do
  args <- getArgs
  case getOpt Permute options args of
      (flags, nonOpts, [])     -> handleFlags flags nonOpts
      (_,     _,       msgs)   -> error $ concat msgs ++ usageInfo header options

data Flag 
   = Version 
   | Help 
   | Numbered
   | Invert
   | Start Int 
   | End Int
   deriving(Eq)

header :: String
header = "Usage: split [options] <input>"

versionInfo :: String
versionInfo = "splitter-0.1 by Robert Massaioli (2012-2013)"

options :: [OptDescr Flag] 
options = 
   [ Option "n" ["numbers"] (NoArg Numbered) "include line numbers in final output"
   , Option "i" ["invert"] (NoArg Invert) "get the opposite of the lines specified"
   , Option "Vv" ["version"] (NoArg Version) "print version number"
   , Option "Hh" ["help"] (NoArg Help) "print this help message"
   ]

handleFlags :: [Flag] -> [String] -> IO ()
handleFlags flags inputs
  | Help `elem` flags = putStrLn (usageInfo header options)
  | Version `elem` flags = putStrLn versionInfo
  | otherwise = case actualRanges of
                  Left error -> do
                     putStrLn . show $ error
                     exitWith (ExitFailure 1)
                  Right realRanges -> runSplit realRanges
  where
    actualRanges :: Either ParseError [Range Integer]
    actualRanges = parseRanges (intercalate "," inputs)

    runSplit :: [Range Integer] -> IO ()
    runSplit ranges  = do
         lines <- liftM lines getContents
         go 1 lines
      where
         go :: Integer -> [String] -> IO ()
         go _       []        = return ()
         go lineNum (line:ls) = do
            when (inRanges realRanges lineNum) $ do
               when includeNumbers . putStr $ show lineNum ++ " "
               putStrLn line
            go (lineNum + 1) ls

         includeNumbers = Numbered `elem` flags
         
         realRanges = if Invert `elem` flags
            then invert ranges
            else ranges