Hsed-0.2: src/Main.hs
-- |
-- Module : Main
-- Copyright : (c) Vitaliy Rukavishnikov
-- License : BSD-style (see the file LICENSE)
--
-- Maintainer : virukav@gmail.com
-- Stability : experimental
-- Portability : non-portable
--
-- See "The Open Group Base Specifications Issue 7" for the requirements
-- This version of the Haskell Sed uses regex-posix package to parse all regular
-- expressions. At the moment it doesn't supports the back-references in the RE.
module Main where
import System.IO
import System (getArgs)
import System.FilePath (splitFileName)
import Control.Monad (unless, when)
import qualified Control.Exception as E
import qualified System.FilePath.Glob as G (compile, globDir1)
import Hsed.StreamEd (runSed)
import Hsed.SedState
data SedArgs = SedArgs {
files :: [FilePath],
script :: String,
defOut :: Maybe Bool
} deriving Show
main :: IO ()
main = do
args <- getArgs
if null args || head args == "--help" then do
putStrLn usage
return ()
else do
SedArgs fs sed out <- parseArgs args
let setDef b = initEnv {defOutput_ = b}
runSed fs sed (maybe initEnv setDef out)
return ()
-- | Parse Sed program's arguments
parseArgs :: [String] -> IO SedArgs
parseArgs xs = parseArgs' xs (SedArgs [] "" Nothing) where
parseArgs' [] sargs = return sargs
parseArgs' [x] sargs
| x == "-n" = return $ sargs {defOut = Just False}
| otherwise = parseCmds x sargs
parseArgs' (x:y:ys) sargs
| x == "-e" = parseArgs' ys (addCmd sargs y)
| x == "-f" = do
sed <- System.IO.readFile y `catch` openFileError y
parseArgs' ys (addCmd sargs sed)
| x == "-n" = parseArgs' (y:ys) (sargs {defOut = Just False})
| otherwise = parseCmds x sargs >>= \sargs' -> parseArgs' (y:ys) sargs'
where
addCmd s@sargs x' = s {script = script s ++ ('\n':x')}
openFileError :: String -> E.IOException -> IO [a]
openFileError f e = putStr ("Error: Couldn't open " ++ f ++ ": " ++
show (e :: E.IOException)) >> return []
-- | Parse Sed program's embedded commands and the input files arguments
parseCmds :: String -> SedArgs -> IO SedArgs
parseCmds x s@(SedArgs files script _) =
if null script then return $ s {script = x}
else do
let (dir, fp) = splitFileName x
fs <- G.globDir1 (G.compile fp) dir
if null fs then error $ fp ++ ": No such file or directory"
else return $ s {files = files ++ fs}
usage :: String
usage = unlines help
where help = ["usage: Hsed [-n] script [file...]",
" Hsed [-n] -e script [-e script]... [-f script_file]... [file...]",
" Hsed [-n] [-e script]... -f script_file [-f script_file]... [file...]"
]