{- - This example is similar to the commandline uconv program. - Author: Conrad Parker, July 2007 - Adapted by: Audrey Tang, 2008 Usage: huconv [options] filename -h, -? --help, --usage Display this help and exit -f encoding --from-code=encoding Convert characters from encoding -t encoding --to-code=encoding Convert characters to encoding -o file --output=file Specify output file (instead of stdout) -} module Main where import Control.Monad (when) import System.Environment (getArgs, getProgName) import System.Console.GetOpt (getOpt, usageInfo, OptDescr(..), ArgDescr(..), ArgOrder(..)) import System.Exit (exitFailure) import qualified Data.ByteString as S import qualified Codec.Text.UConv as UConv ------------------------------------------------------------ -- main -- main :: IO () main = do args <- getArgs (config, filenames) <- processArgs args let inputFile = head filenames input <- case inputFile of "-" -> S.getContents _ -> S.readFile inputFile output <- UConv.convert (fromEncoding config) (toEncoding config) input case outputFile config of "-" -> S.putStr output fn -> S.writeFile fn output ------------------------------------------------------------ -- Option handling -- data Config = Config { fromEncoding :: String, toEncoding :: String, outputFile :: FilePath } deriving Show defaultConfig = Config { fromEncoding = "", toEncoding = "", outputFile = "-" } data Option = Help | FromEncoding String | ToEncoding String | OutputFile String deriving Eq options :: [OptDescr Option] options = [ Option ['h', '?'] ["help", "usage"] (NoArg Help) "Display this help and exit" , Option ['f'] ["from-code"] (ReqArg FromEncoding "encoding") "Convert characters from encoding" , Option ['t'] ["to-code"] (ReqArg ToEncoding "encoding") "Convert characters to encoding" , Option ['o'] ["output"] (ReqArg OutputFile "file") "Specify output file (instead of stdout)" ] processArgs :: [String] -> IO (Config, [String]) processArgs args = do case getOpt Permute options args of (opts, args, errs) -> do processHelp opts let config = processConfig defaultConfig opts checkConfig errs config args return (config, args) checkConfig :: [String] -> Config -> [String] -> IO () checkConfig errs config filenames = do when (any null [fromEncoding config, toEncoding config] || null filenames) $ processHelp [Help] when (not (null errs)) $ do mapM_ putStr errs processHelp [Help] processHelp :: [Option] -> IO () processHelp opts = do name <- getProgName let header = "\nUsage: " ++ name ++ " [options] filename\n" when (Help `elem` opts) $ do putStrLn $ usageInfo header options exitFailure processConfig :: Config -> [Option] -> Config processConfig = foldl processOneOption where processOneOption config (FromEncoding f) = config {fromEncoding = f} processOneOption config (ToEncoding t) = config {toEncoding = t} processOneOption config (OutputFile o) = config {outputFile = o}