module Main where import Control.Exception (Handler(..)) import qualified Control.Exception as E (catches) import Control.Monad (when) import Data.List (isPrefixOf, intercalate) import Data.Maybe (isNothing) import Distribution.Cab import System.Console.GetOpt (ArgOrder(..), OptDescr(..), getOpt') import System.Environment (getArgs) import System.Exit (ExitCode, exitFailure) import System.IO import Commands import Doc import Help import Options import Run import Types ---------------------------------------------------------------- main :: IO () main = flip E.catches handlers $ do oargs <- getArgs let pargs = parseArgs getOptDB oargs checkOptions1 pargs illegalOptionsAndExit let Right (args,opts0) = pargs when (args == []) helpAndExit when (OptHelp `elem` opts0) $ helpCommandAndExit args [] [] let opts1 = filter (/= OptHelp) opts0 act:params = args mcmdspec = commandSpecByName act (commandDB helpCommandAndExit) when (isNothing mcmdspec) (illegalCommandAndExit act) let Just cmdspec = mcmdspec checkOptions2 opts1 cmdspec oargs illegalOptionsAndExit run cmdspec params opts1 where handlers = [Handler handleExit] handleExit :: ExitCode -> IO () handleExit _ = return () ---------------------------------------------------------------- illegalCommandAndExit :: String -> IO () illegalCommandAndExit x = do hPutStrLn stderr $ "Illegal command: " ++ x exitFailure ---------------------------------------------------------------- illegalOptionsAndExit :: UnknownOptPrinter illegalOptionsAndExit xs = do -- FixME hPutStrLn stderr $ "Illegal options: " ++ intercalate " " xs exitFailure ---------------------------------------------------------------- type ParsedArgs = Either [UnknownOpt] ([Arg],[Option]) parseArgs :: [GetOptSpec] -> [Arg] -> ParsedArgs parseArgs db args = case getOpt' Permute db args of (o,n,[],[]) -> Right (n,o) (_,_,unknowns,_) -> Left unknowns ---------------------------------------------------------------- type UnknownOpt = String type UnknownOptPrinter = [UnknownOpt] -> IO () ---------------------------------------------------------------- checkOptions1 :: ParsedArgs -> UnknownOptPrinter -> IO () checkOptions1 (Left es) func = func es checkOptions1 _ _ = return () ---------------------------------------------------------------- checkOptions2 :: [Option] -> CommandSpec -> [Arg] -> UnknownOptPrinter -> IO () checkOptions2 opts cmdspec oargs func = when (unknowns /= []) $ func (concatMap (resolveOptionString oargs) unknowns) where unknowns = unknownOptions opts cmdspec unknownOptions :: [Option] -> CommandSpec -> [Switch] unknownOptions opts cmdspec = chk specified supported where chk [] _ = [] chk (x:xs) ys | x `elem` ys = chk xs ys | otherwise = x : chk xs ys specified = map toSwitch opts supported = map fst $ switches cmdspec resolveOptionString :: [Arg] -> Switch -> [UnknownOpt] resolveOptionString oargs sw = case lookup sw optionDB of Nothing -> error "resolveOptionString" Just gspec -> let (s,l) = getOptNames gspec in checkShort s ++ checkLong l where checkShort s = filter (==s) oargs checkLong l = filter (l `isPrefixOf`) oargs getOptNames :: GetOptSpec -> (String,String) getOptNames (Option (c:_) (s:_) _ _) = ('-':[c],'-':'-':s) getOptNames _ = error "getOptNames"