{-
Copyright 2013 Mario Pastorelli (pastorelli.mario@gmail.com)
This file is part of HSProcess.
HSProcess 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 3 of the License, or
(at your option) any later version.
HSProcess 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 HSProcess. If not, see .
-}
module System.Console.HSProcess.Options where
import Data.ByteString (ByteString)
import Control.Arrow (first)
import qualified Data.ByteString.Char8 as C8
import qualified Data.List as L
import qualified System.FilePath as FP
import System.Console.GetOpt
import Data.Maybe
data Options = Options { optDelimiter :: Maybe ByteString
, optRecompile :: Bool
, optMap :: Bool
, optEval :: Bool
, optHelp :: Bool
, optIgnoreErrors :: Bool
, optModuleFile :: Maybe FP.FilePath}
deriving Show
defaultOptions :: Options
defaultOptions = Options { optDelimiter = Nothing
, optRecompile = False
, optMap = False
, optEval = False
, optHelp = False
, optIgnoreErrors = True
, optModuleFile = Nothing }
delimiter :: ByteString -> ByteString
delimiter = C8.concat . (\ls -> L.head ls:L.map subFirst (L.tail ls))
. C8.splitWith (== '\\')
where subFirst s = case C8.head s of
'n' -> C8.cons '\n' $ C8.tail s
't' -> C8.cons '\t' $ C8.tail s
_ -> s
options :: [OptDescr (Options -> Options)]
options =
[ Option ['d'] ["delimiter"] (OptArg delimiterAction "") delimiterHelp
, Option ['r'] ["recompile"] (NoArg setRecompile) recompileHelp
, Option ['m'] ["map"] (NoArg $ \o -> o{ optMap = True}) mapHelp
, Option ['e'] ["eval"] (NoArg $ \o -> o{ optEval = True}) evalHelp
, Option ['h'] ["help"] (NoArg $ \o -> o{ optHelp = True }) helpHelp
, Option ['E'] ["errors"] (NoArg ignoreErrorsAction) ignoreErrorsHelp
]
where delimiterAction s o = let d = case s of
Nothing -> C8.singleton '\n'
Just rd -> delimiter (C8.pack rd)
in o{ optDelimiter = Just d }
delimiterHelp = "String used as delimiter"
setRecompile o = o{ optRecompile = True}
recompileHelp = "Recompile toolkit.hs"
mapHelp = "Map a command over each string separated by the delimiter"
evalHelp = "Ignore stdin and the input file and evaluate the "
++ "user expression"
helpHelp = "Print help and exit"
ignoreErrorsAction o = o{ optIgnoreErrors = False}
ignoreErrorsHelp = "When set, errors in user code block "
++ "execution. When is not set,"
++ " errors don't block the execution and "
++ "are logged to stderr. Default: False"
compileOpts :: [String] -> Either [String] (Options,[String])
compileOpts argv =
case getOpt Permute options argv of
(os,nos,[]) -> Right (L.foldl (.) id os defaultOptions, nos)
(_,_,errs) -> Left errs
postOptsProcessing :: Maybe String
-> (Options,[String])
-> Either [String] (Options,[String])
postOptsProcessing defaultConfigFile (opts,args) =
if length args < 1
then errorArg
else solveAmbiguities (opts,args) >>= Right . first process
where
errorArg = Left [
"Missing argument representing the function to evaluate:\n"
++ "\t opts: " ++ show opts
++ "\n\targs: " ++ show args
]
process :: Options -> Options
process = optModuleFileProcess . optMapProcess
solveAmbiguities :: (Options,[String])
-> Either [String] (Options,[String])
solveAmbiguities (os,as) =
if optEval os && (optMap os || isJust (optDelimiter os))
then Left ["Cannot set both -e and -m/-d options"]
else Right (os,as)
optModuleFileProcess os = if isNothing (optModuleFile os)
then os{ optModuleFile = defaultConfigFile}
else os
optMapProcess os = if optMap os && isNothing (optDelimiter os)
then os{ optDelimiter = Just (C8.singleton '\n')}
else os