{- odec - command line utility for data decoding Copyright (C) 2008 Magnus Therning This program 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. This program 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 this program. If not, see . -} module Main ( main ) where import Codec.Binary.DataEncoding import Data.Maybe import Data.Version (showVersion) import Data.Word import System import System.Console.GetOpt import Control.Exception as CE import System.Directory import qualified Data.ByteString as BS import Paths_omnicodec (version) ver :: String ver = "omnicode decode (odec) " ++ (showVersion version) ++ "\nCopyright 2007-2010 Magnus Therning " -- {{{1 Options data DecOptions = DecOptions { optDecode :: [String] -> [Maybe Word8], optRead :: IO String, optWrite :: BS.ByteString -> IO (), optFn :: Maybe String -- needed in case we need to clean up later on } defaultOptions :: DecOptions defaultOptions = DecOptions { optDecode = decode' uu . unchop uu, optRead = getContents, optWrite = BS.putStr, optFn = Nothing } -- {{{2 Command line options :: [OptDescr (DecOptions -> IO DecOptions)] options = [ Option "o" ["output"] (ReqArg setOptOutput "FILE") "output to file", Option "c" ["codec"] (ReqArg setOptCodec "CODEC") "use codec (uu,xx,qp,py,b85,b64,b64u,b32,b32h,b16)", Option "" ["version"] (NoArg optShowVersion) "", Option "h" ["help"] (NoArg optShowHelp) "" ] -- {{{2 Processing command line setOptOutput :: FilePath -> DecOptions -> IO DecOptions setOptOutput fn opts = return opts { optWrite = BS.writeFile fn, optFn = Just fn } setOptCodec :: String -> DecOptions -> IO DecOptions setOptCodec codec opts = case codec of "uu" -> return opts { optDecode = decode' uu . unchop uu } "xx" -> return opts { optDecode = decode' xx . unchop xx } "qp" -> return opts { optDecode = decode' qp . unchop qp } "py" -> return opts { optDecode = decode' py . unchop py } "b85" -> return opts { optDecode = decode' base85 . unchop base85 } "b64" -> return opts { optDecode = decode' base64 . unchop base64 } "b64u" -> return opts { optDecode = decode' base64Url . unchop base64Url } "b32" -> return opts { optDecode = decode' base32 . unchop base32 } "b32h" -> return opts { optDecode = decode' base32Hex . unchop base32Hex } "b16" -> return opts { optDecode = decode' base16 . unchop base16 } _ -> error "Unknown encoding." optShowVersion :: a -> IO DecOptions optShowVersion _ = putStrLn ver >> exitWith ExitSuccess optShowHelp :: DecOptions -> IO DecOptions optShowHelp _ = putStrLn (usageInfo "Usage:" options) >> exitWith ExitSuccess processFileName :: [String] -> IO DecOptions processFileName (fn:_) = return defaultOptions { optRead = readFile fn } processFileName _ = return defaultOptions -- {{{1 decode' _decode :: DecOptions -> String -> IO BS.ByteString _decode opts = return . BS.pack. map (fromMaybe (error "Illegal character")) . optDecode opts . lines -- {{{1 main main :: IO () main = do args <- getArgs let (actions, nonOpts, _) = getOpt RequireOrder options args opts <- foldl (>>=) (processFileName nonOpts) actions CE.catch (optRead opts >>= _decode opts >>= optWrite opts) (\ (CE.SomeException e) -> maybe (return ()) removeFile (optFn opts) >> throwIO e)