module ProgramOptions ( Options(..), fillFromLog, parseOptions, logOptions, writeError, versionText ) where import Control.Monad.State import Control.Applicative hiding (many) import Text.ParserCombinators.Parsec hiding ((<|>),State,Line) import System.Console.GetOpt import System.FilePath import Paths_adblock2privoxy (version) import Data.Version (showVersion) data Options = Options { _showVersion :: Bool , _privoxyDir :: FilePath , _webDir :: FilePath , _taskFile :: FilePath , _cssDomain :: String , _forced :: Bool } options :: [OptDescr (Options -> Options)] options = [ Option "v" ["version"] (NoArg (\ opts -> opts { _showVersion = True })) "Show version number" , Option "p" ["privoxyDir"] (ReqArg (\ f opts -> opts { _privoxyDir = f }) "PATH") "Privoxy config output path" , Option "w" ["webDir"] (ReqArg (\ f opts -> opts { _webDir = f }) "PATH") "Css files output path (optional, privoxyDir is used by default)" , Option "d" ["domainCSS"] (ReqArg (\ d opts -> opts { _cssDomain = d }) "DOMAIN") "Domain of CSS web server (required for Element Hide functionality)" , Option "t" ["taskFile"] (ReqArg (\ f opts -> opts { _taskFile = f }) "PATH") "Path to task file containing urls to process and options. privoxyDir, webDir and domainCSS values are taken from this file if not specified explicitly" , Option "f" ["forced"] (NoArg (\ opts -> opts { _forced = True })) "Run even if no sources are expired" ] parseOptions :: [String] -> IO (Options, [String]) parseOptions argv = case getOpt Permute options argv of (opts,nonOpts,[] ) -> case foldl (flip id) emptyOptions opts of Options False "" _ "" _ _ -> writeError "Privoxy dir or task file should be specified.\n" opts'@Options{_showVersion = True} -> return (opts', nonOpts) opts' -> return (setDefaults opts', nonOpts) (_,_,errs) -> writeError $ concat errs where setDefaults opts@(Options _ (privoxyDir@(_:_)) "" _ _ _) = setDefaults opts{ _webDir = privoxyDir } setDefaults opts@(Options _ privoxyDir _ "" _ _) = setDefaults opts{ _taskFile = privoxyDir "ab2p.task" } setDefaults opts = opts versionText :: String versionText = "adblock2privoxy version " ++ showVersion version writeError :: String -> IO a writeError msg = ioError $ userError $ msg ++ "\n" ++ usageInfo header options where header = versionText ++ "\nSee home page for more details and updates: https://github.com/essandess/adblock2privoxy\n" ++ "Usage: adblock2privoxy [OPTION...] [URL...]" logOptions :: Options -> [String] logOptions options' = [ startMark, "Privoxy path: " ++ _privoxyDir options', "Web path: " ++ _webDir options', "CSS web server domain: " ++ _cssDomain options', endMark, ""] startMark :: String startMark = "----- options -----" endMark :: String endMark = "------- end ------" emptyOptions :: Options emptyOptions = Options False "" "" "" "" False fillFromLog :: Options -> [String] -> Options fillFromLog existing lns = execState (sequence $ parseLogOptions <$> lns') existing where lns' = filter (not.null) $ takeWhile (/= endMark).dropWhile (/= startMark) $ lns parseLogOptions :: String -> State Options () parseLogOptions text = do info <- get let ifEmpty getter x = let oldValue = getter info in if null oldValue then x else oldValue privoxyPathParser = (\x -> info{_privoxyDir = ifEmpty _privoxyDir x}) <$> (string "Privoxy path: " *> many1 anyChar) webPathParser = (\x -> info{_webDir = ifEmpty _webDir x}) <$> (string "Web path: " *> many1 anyChar) cssDomainParser = (\x -> info{_cssDomain = ifEmpty _cssDomain x}) <$> (string "CSS web server domain: " *> many1 anyChar) stringParser = skipMany (char ' ') *> (try privoxyPathParser <|> try webPathParser <|> cssDomainParser) case parse stringParser "" text of Left _ -> return () Right info' -> put info'