diff --git a/omnicodec.cabal b/omnicodec.cabal
--- a/omnicodec.cabal
+++ b/omnicodec.cabal
@@ -1,26 +1,24 @@
 name: omnicodec
-version: 0.4.0
+version: 0.5
 license: GPL
 license-file: COPYING
 author: Magnus Therning
 maintainer: magnus@therning.org
-copyright: Magnus Therning, 2007-2010
+copyright: Magnus Therning, 2007-2011
 synopsis: data encoding and decoding command line utilities
 description: Two simple command line tools built on dataenc.
 build-type: Simple
 category: Codec
-cabal-version: >= 1.2
+cabal-version: >= 1.6
 
 executable odec
-  main-is: odec.hs
-  hs-source-dirs: src
-  build-depends: base >= 4.0.0 && < 4.3, dataenc >= 0.13, directory, filepath,
-      haskell98, bytestring
-  ghc-options: -Wall
+    main-is: odec.hs
+    hs-source-dirs: src
+    build-depends: base ==4.2.*, cmdargs ==0.6.*, bytestring ==0.9.*,
+        mtl ==1.1.*, dataenc ==0.14.*
+    ghc-options: -Wall
 
 executable oenc
-  main-is: oenc.hs
-  hs-source-dirs: src
-  build-depends: base >= 4.0.0 && < 4.3, dataenc >= 0.13, directory, filepath,
-      haskell98, bytestring
-  ghc-options: -Wall
+    main-is: oenc.hs
+    hs-source-dirs: src
+    ghc-options: -Wall
diff --git a/src/odec.hs b/src/odec.hs
--- a/src/odec.hs
+++ b/src/odec.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+
 {-
 odec - command line utility for data decoding
 Copyright (C) 2008  Magnus Therning
@@ -20,84 +22,121 @@
     ( 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)
 
+import Codec.Binary.Base64 as B64
+import qualified Codec.Binary.Base64Url as B64U
+import qualified Codec.Binary.Base32 as B32
+import qualified Codec.Binary.Base32Hex as B32H
+import qualified Codec.Binary.Base16 as B16
+import qualified Codec.Binary.Base85 as B85
+import qualified Codec.Binary.PythonString as PS
+import qualified Codec.Binary.QuotedPrintable as QP
+import qualified Codec.Binary.Url as Url
+import qualified Codec.Binary.Uu as Uu
+import qualified Codec.Binary.Xx as Xx
+import Data.ByteString.Iteratee
+import Data.ByteString.Iteratee.Internals
+
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Char8 as BSC
+import System.Console.CmdArgs
+import Data.Version(showVersion)
+import System.IO
+import Data.Maybe
+
+-- {{{1 command line options
 ver :: String
 ver = "omnicode decode (odec) " ++ (showVersion version)
-    ++ "\nCopyright 2007-2010 Magnus Therning <magnus@therning.org>"
-
--- {{{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
-    }
+    ++ "\nCopyright 2007-2011 Magnus Therning <magnus@therning.org>"
 
-defaultOptions :: DecOptions
-defaultOptions = DecOptions {
-    optDecode = decode' uu . unchop uu,
-    optRead = getContents,
-    optWrite = BS.putStr,
-    optFn = Nothing
-    }
+data Codec = B64 | B64U | B32 | B32H | B16 | B85 | PS | QP | Url | Uu | Xx
+    deriving(Show, Eq, Data, Typeable)
 
--- {{{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) ""
+codecMap :: [(Codec, DecIncData String -> DecIncRes String)]
+codecMap =
+    [ (B64, B64.decodeInc)
+    , (B64U, B64U.decodeInc)
+    , (B32, B32.decodeInc)
+    , (B32H, B32H.decodeInc)
+    , (B16, B16.decodeInc)
+    , (B85, B85.decodeInc)
+    , (PS, PS.decodeInc)
+    , (QP, QP.decodeInc)
+    , (Url, Url.decodeInc)
+    , (Uu, Uu.decodeInc)
+    , (Xx, Xx.decodeInc)
     ]
 
--- {{{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
+data MyArgs = MyArgs { argInput :: Maybe FilePath, argOutput :: Maybe FilePath, argCodec :: Codec }
+    deriving(Show, Data, Typeable)
 
-optShowHelp :: DecOptions -> IO DecOptions
-optShowHelp _ = putStrLn (usageInfo "Usage:" options) >> exitWith ExitSuccess
+myArgs :: MyArgs
+myArgs = MyArgs
+    { argInput = Nothing &= name "i" &= name "in" &= explicit &= typFile &= help "read encoded data from file"
+    , argOutput = Nothing &= name "o" &= name "out" &= explicit &= typFile &= help "write decoded data to file"
+    , argCodec = B64 &= name "c" &= name "codec" &= explicit &= typ "CODEC" &= help "codec b64, b64u, b32, b32h, b16, b85, ps, qp, url, uu, xx (b64)"
+    } &= summary ver &= details
+        [ "Decoder tool for multiple encodings:"
+        , " b64  - base64 (default)"
+        , " b64u - base64url"
+        , " b32  - base32"
+        , " b32h - base32hex"
+        , " b16  - base16"
+        , " b85  - base85"
+        , " ps   - python string escaping"
+        , " qp   - quoted printable"
+        , " url  - url encoding"
+        , " uu   - uu encoding"
+        , " xx   - xx encoding"
+        ]
 
-processFileName :: [String] -> IO DecOptions
-processFileName (fn:_) = return defaultOptions { optRead = readFile fn }
-processFileName _ = return defaultOptions
+-- {{{1 decode enumeratee
+decEnumeratee :: Monad m => (DecIncData String -> DecIncRes String) -> Enumeratee m a
+decEnumeratee decF iter = Iteratee $ step decF iter
+    where
+        step f i Eof = let
+                d = f DDone
+            in do
+                case d of
+                    DFinal dbs _ -> do
+                        ir <- runIteratee i (Chunk $ BS.pack dbs)
+                        case ir of
+                            Done a _ -> return $ Done (Iteratee $ \ _ -> return $ Done a Eof) Eof
+                            NeedAnotherChunk i' -> do
+                                ir' <- runIteratee i' Eof
+                                case ir' of
+                                    Done a _ -> return $ Done (Iteratee $ \ _ -> return $ Done a Eof) Eof
+                                    NeedAnotherChunk _ -> error "decEnumeratee: inner iteratee diverges on Eof"
+                    DFail _ _ -> error "decEnumeratee: decoder failed on data"
+                    DPart _ _ -> error "decEnumeratee: decoder didn't terminate on DDone"
 
--- {{{1 decode'
-_decode :: DecOptions -> String -> IO BS.ByteString
-_decode opts = return .  BS.pack. map (fromMaybe (error "Illegal character")) . optDecode opts . lines
+        step f i (Chunk bs) = let
+                d = f (DChunk $ BSC.unpack bs)
+            in do
+                case d of
+                    DFinal dbs r -> do
+                        ir <- runIteratee i (Chunk $ BS.pack dbs)
+                        case ir of
+                            Done a _ -> return $ Done (Iteratee $ \ _ -> return $ Done a (Chunk $ BSC.pack r)) (Chunk $ BSC.pack r)
+                            NeedAnotherChunk i' -> do
+                                ir' <- runIteratee i' Eof
+                                case ir' of
+                                    Done a _ -> return $ Done (Iteratee $ \ _ -> return $ Done a Eof) Eof
+                                    NeedAnotherChunk _ -> error "decEnumeratee: inner iteratee diverges on Eof"
+                    DFail _ _ -> error "decEnumeratee: decoder failed on data"
+                    DPart dbs f' -> do
+                        ir <- runIteratee i (Chunk $ BS.pack dbs)
+                        case ir of
+                            Done a _ -> return $ Done (Iteratee $ \ _ -> return $ Done a (Chunk BS.empty)) (Chunk BS.empty)
+                            NeedAnotherChunk i' -> return $ NeedAnotherChunk $ Iteratee $ step f' i'
 
 -- {{{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)
+    cmdArgs myArgs >>= \ a -> do
+    hIn <- maybe (return stdin) (\ fn -> openFile fn ReadMode) (argInput a)
+    hOut <- maybe (return stdout) (\ fn -> openFile fn WriteMode) (argOutput a)
+    let dI = fromJust $ lookup (argCodec a) codecMap
+    (enumHandle hIn $ decEnumeratee dI (sinkHandle hOut)) >>= run >>= run
+    hClose hOut
diff --git a/src/oenc.hs b/src/oenc.hs
--- a/src/oenc.hs
+++ b/src/oenc.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+
 {-
 oenc - command line utility for data encoding
 Copyright (C) 2008  Magnus Therning
@@ -16,80 +18,106 @@
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 -}
 
-module Main
-    where
-
-import Codec.Binary.DataEncoding
-import Data.Version (showVersion)
-import Data.Word
-import System
-import System.Console.GetOpt
-import qualified Data.ByteString as BS
+module Main where
 
 import Paths_omnicodec (version)
 
+import Codec.Binary.Base64 as B64
+import qualified Codec.Binary.Base64Url as B64U
+import qualified Codec.Binary.Base32 as B32
+import qualified Codec.Binary.Base32Hex as B32H
+import qualified Codec.Binary.Base16 as B16
+import qualified Codec.Binary.Base85 as B85
+import qualified Codec.Binary.PythonString as PS
+import qualified Codec.Binary.QuotedPrintable as QP
+import qualified Codec.Binary.Url as Url
+import qualified Codec.Binary.Uu as Uu
+import qualified Codec.Binary.Xx as Xx
+import Data.ByteString.Iteratee
+import Data.ByteString.Iteratee.Internals
+
+import Data.Version(showVersion)
+import System.Console.CmdArgs
+import qualified Data.ByteString as BS
+import qualified Data.ByteString.Char8 as BSC
+import System.IO
+import Data.Maybe
+
+-- {{{1 command line options
 ver :: String
 ver = "omnicode encode (oenc) " ++ (showVersion version)
-    ++ "\nCopyright 2007-2010 Magnus Therning <magnus@therning.org>"
-
--- {{{1 Options
-data EncOptions = EncOptions {
-    optEncode :: [Word8] -> [String],
-    optRead :: IO BS.ByteString,
-    optWrite :: String -> IO ()
-    }
+    ++ "\nCopyright 2007-2011 Magnus Therning <magnus@therning.org>"
 
-defaultOptions :: EncOptions
-defaultOptions = EncOptions {
-    optEncode = chop uu 61 . encode uu,
-    optRead = BS.getContents,
-    optWrite = putStr
-    }
+data Codec = B64 | B64U | B32 | B32H | B16 | B85 | PS | QP | Url | Uu | Xx
+    deriving(Show, Eq, Data, Typeable)
 
-options :: [OptDescr (EncOptions -> IO EncOptions)]
-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) ""
+codecMap :: [(Codec, EncIncData -> EncIncRes String)]
+codecMap =
+    [ (B64, B64.encodeInc)
+    , (B64U, B64U.encodeInc)
+    , (B32, B32.encodeInc)
+    , (B32H, B32H.encodeInc)
+    , (B16, B16.encodeInc)
+    , (B85, B85.encodeInc)
+    , (PS, PS.encodeInc)
+    , (QP, QP.encodeInc)
+    , (Url, Url.encodeInc)
+    , (Uu, Uu.encodeInc)
+    , (Xx, Xx.encodeInc)
     ]
 
--- {{{2 option actions
-setOptCodec :: String -> EncOptions -> IO EncOptions
-setOptCodec codec opts = case codec of
-    "uu" -> return opts { optEncode = chop uu 61 . encode uu }
-    "xx" -> return opts { optEncode = chop xx 61 . encode xx }
-    "qp" -> return opts { optEncode = chop qp 60 . encode qp }
-    "py" -> return opts { optEncode = chop py 60 . encode py }
-    "b85" -> return opts { optEncode = chop base85 60 . encode base85 }
-    "b64" -> return opts { optEncode = chop base64 60 . encode base64 }
-    "b64u" -> return opts { optEncode = chop base64Url 60 . encode base64Url }
-    "b32" -> return opts { optEncode = chop base32 60 . encode base32 }
-    "b32h" -> return opts { optEncode = chop base32Hex 60 . encode base32Hex }
-    "b16" -> return opts { optEncode = chop base16 60 . encode base16 }
-    _ -> error "Unknown encoding."
-
-setOptOutput :: FilePath -> EncOptions -> IO EncOptions
-setOptOutput fn opts = return opts { optWrite = writeFile fn }
-
-optShowVersion :: EncOptions -> IO EncOptions
-optShowVersion _ = putStrLn ver >> exitWith ExitSuccess
-
-optShowHelp :: EncOptions -> IO EncOptions
-optShowHelp _ = putStr (usageInfo "Usage:" options) >> exitWith ExitSuccess
+data MyArgs = MyArgs { argInput :: Maybe FilePath, argOutput :: Maybe FilePath, argCodec :: Codec }
+    deriving(Show, Data, Typeable)
 
-processFileName :: [String] -> IO EncOptions
-processFileName (fn:_) = return defaultOptions { optRead = BS.readFile fn }
-processFileName _ = return defaultOptions
+myArgs :: MyArgs
+myArgs = MyArgs
+    { argInput = Nothing &= name "i" &= name "in" &= explicit &= typFile &= help "read data from file"
+    , argOutput = Nothing &= name "o" &= name "out" &= explicit &= typFile &= help "write encoded data to file"
+    , argCodec = B64 &= name "c" &= name "codec" &= explicit &= typ "CODEC" &= help "codec b64, b64u, b32, b32h, b16, b85, ps, qp, url, uu, xx (b64)"
+    } &= summary ver &= details
+        [ "Encoder tool for multiple encodings:"
+        , " b64  - base64 (default)"
+        , " b64u - base64url"
+        , " b32  - base32"
+        , " b32h - base32hex"
+        , " b16  - base16"
+        , " b85  - base85"
+        , " ps   - python string escaping"
+        , " qp   - quoted printable"
+        , " url  - url encoding"
+        , " uu   - uu encoding"
+        , " xx   - xx encoding"
+        ]
 
--- {{{1 encode
-_encode :: EncOptions -> BS.ByteString -> IO String
-_encode opts = return . unlines . optEncode opts . BS.unpack
+-- {{{1 encode enumeratee
+encEnumeratee :: Monad m => (EncIncData -> EncIncRes String) -> Enumeratee m a
+encEnumeratee encF iter = Iteratee $ step encF iter
+    where
+        step f i Eof = let
+                EFinal ebs = f EDone
+            in do
+                ir <- runIteratee i (Chunk $ BSC.pack ebs)
+                case ir of
+                    Done a _ -> return $ Done (Iteratee $ \ _ -> return $ Done a Eof) Eof
+                    NeedAnotherChunk i' -> do
+                        ir' <- runIteratee i' Eof
+                        case ir' of
+                            Done a _ -> return $ Done (Iteratee $ \ _ -> return $ Done a Eof) Eof
+                            NeedAnotherChunk _ -> error "encEnumeratee: inner iteratee diverges on Eof"
+        step f i (Chunk bs) = let
+                EPart ebs f' = f (EChunk $ BS.unpack bs)
+            in do
+                ir <- runIteratee i (Chunk $ BSC.pack ebs)
+                case ir of
+                    Done a _ -> return $ Done (Iteratee $ \ _ -> return $ Done a (Chunk BS.empty)) (Chunk BS.empty)
+                    NeedAnotherChunk i' -> return $ NeedAnotherChunk $ Iteratee $ step f' i'
 
 -- {{{1 main
 main :: IO ()
 main = do
-    args <- getArgs
-    let (actions, nonOpts, _) = getOpt RequireOrder options args
-    opts <- foldl (>>=) (processFileName nonOpts) actions
-    optRead opts >>= _encode opts >>= optWrite opts
+    cmdArgs myArgs >>= \ a -> do
+    hIn <- maybe (return stdin) (\ fn -> openFile fn ReadMode) (argInput a)
+    hOut <- maybe (return stdout) (\ fn -> openFile fn WriteMode) (argOutput a)
+    let eI = fromJust $ lookup (argCodec a) codecMap
+    (enumHandle hIn $ encEnumeratee eI (sinkHandle hOut)) >>= run >>= run
+    hClose hOut
