diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,35 +1,68 @@
 # ip6addr ![CI](https://github.com/MichelBoucey/ip6addr/actions/workflows/haskell-ci.yml/badge.svg)
 
-A commandline tool that validates and generates IPv6 address text representations
+## 1. Goal
 
-* Canonical, in conformation with RFC 5952 (default output)
-* Pure, i.e. rewriting IPv4 address if present
+`ip6addr` is a commandline tool that validates and generates IPv6 address text representations, based upon [the library IPv6Addr](https://github.com/MichelBoucey/IPv6Addr) :
+
+* Canonical, in conformation with [RFC 5952](https://www.rfc-editor.org/rfc/rfc5952) (default output)
+* Pure, *i.e.* force the rewriting of IPv4 address if present
 * Full length
-* Reverse lookup domain name, in conformation with RFC 3596 Section 2.5
+* Reverse lookup domain name, in conformation with [RFC 3596 Section 2.5](https://www.rfc-editor.org/rfc/rfc3596#section-2.5)
 * Windows UNC path name
 * Random generation for test purpose  
 
+## 2. Usage
 
+```
+ip6addr v2.0.0 (c) Michel Boucey 2011-2024
+
+Usage: ip6addr [-v|--version]
+               [(-c|--canonical) | (-n|--no-ipv4) | (-f|--full-length) |
+                 (-p|--ptr) | (-w|--windows-unc) | (-r|--random)]
+               [-q|--quantity ARG] [-s|--prefix ARG] [-d|--no-newline]
+               [IPv6 address]
+
+  ip6addr
+
+Available options:
+  -v,--version             Show version
+  -c,--canonical           In conformation with RFC 5952 (default output)
+  -n,--no-ipv4             Force the rewriting of the IPv4 address if present to
+                           get a pure IPv6 address made of nibbles only
+  -f,--full-length         Full IPv6 address length
+  -p,--ptr                 PTR reverse mapping
+  -w,--windows-unc         Windows UNC path name
+  -r,--random              Random generation
+  -q,--quantity ARG        Amount of random addresses to generate
+  -s,--prefix ARG          Set a prefix for random addresses to generate
+  -d,--no-newline          Do not output trailing newlines
+  -h,--help                Show this help text
+```
+
+*N.B.* : In version 2, flags and arguments have changed from version 1, but the main features are identical.
+
+## 3. Examples
+
 ```bash
-    [user@box ~]$ ip6addr -a 0:0::FFFF:192.0.2.128  
+    [user@box ~]$ ip6addr 0:0::FFFF:192.0.2.128  
     ::ffff:192.0.2.128  
-    [user@box ~]$ ip6addr -o pure -a 0:0::FFFF:192.0.2.128  
+    [user@box ~]$ ip6addr --no-ipv4 0:0::FFFF:192.0.2.128
     ::ffff:c000:280  
-    [user@box ~]$ ip6addr -o arpa -a 0:0::FFFF:192.0.2.128  
-    0.8.2.0.0.0.0.c.f.f.f.f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA.  
-    [user@box ~]$ ip6addr -o unc -a 2001:db8:85a3:8d3:1319:8a2e:370:7348
-    2001-db8-85a3-8d3-1319-8a2e-370-7348.ipv6-literal.net    
-    [user@box ~]$ ip6addr -o full -a 0:0::FFFF:192.0.2.128  
-    0000:0000:0000:0000:0000:ffff:c000:0280  
-    [user@box ~]$ ip6addr -o random  
-    ca18::654a:57ab:2ed7  
-    [user@box ~]$ ip6addr -o random -q 4  
-    488:f7f3:7f7e::6ffd  
-    5b8b:8ab4::f0b8  
-    f191:ecc9:8193:8a2:104c:fec1:0:8c4d  
-    af3b:3ffd:8302:6c56::8623:26  
-    [user@box ~]$ ip6addr -o random -q 3 -p 1234:1ab2::  
-    1234:1a2b::cda6:cf2a:bb1d:d70b  
+    [user@box ~]$ ip6addr --ptr 0:0::FFFF:192.0.2.128
+    0.8.2.0.0.0.0.c.f.f.f.f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA.
+    [user@box ~]$ ip6addr --windows-unc 2001:db8:85a3:8d3:1319:8a2e:370:7348
+    2001-db8-85a3-8d3-1319-8a2e-370-7348.ipv6-literal.net
+    [user@box ~]$ ip6addr --full-length 0:0::FFFF:192.0.2.128
+    0000:0000:0000:0000:0000:ffff:c000:0280
+    [user@box ~]$ ip6addr --random
+    ca18::654a:57ab:2ed7
+    [user@box ~]$ ip6addr --random --quantity 4
+    488:f7f3:7f7e::6ffd
+    5b8b:8ab4::f0b8
+    f191:ecc9:8193:8a2:104c:fec1:0:8c4d
+    af3b:3ffd:8302:6c56::8623:26
+    [user@box ~]$ ip6addr --random --quantity 3 --prefix 1234:1ab2::
+    1234:1a2b::cda6:cf2a:bb1d:d70b
     1234:1a2b::362c:8295:f546:a43a  
     1234:1a2b::1121:ca16:ab5:688a  
 ```
diff --git a/app/Main.hs b/app/Main.hs
deleted file mode 100644
--- a/app/Main.hs
+++ /dev/null
@@ -1,81 +0,0 @@
-{-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE OverloadedStrings  #-}
-{-# LANGUAGE RecordWildCards    #-}
-{-# LANGUAGE TemplateHaskell    #-}
-
-import           Control.Monad          (replicateM_)
-import qualified Data.Text              as T
-import qualified Data.Text.IO           as TIO (hPutStrLn, putStrLn)
-import           Data.Version           (showVersion)
-import           Paths_ip6addr          (version)
-import           System.Console.CmdArgs
-import           System.Exit
-import           System.IO              (stderr)
-
-import           Text.IPv6Addr
-
-data Input = Input
-  { output   :: String
-  , address  :: String
-  , quantity :: Int
-  , prefix   :: String
-  } deriving (Show, Data, Typeable)
-
-ip6addrInput :: Input
-ip6addrInput = Input
-  { address = mempty
-    &= typ " <IPv6 address>"
-  , output = "canonical"
-    &= typ " [canonical|pure|full|arpa|unc|random]"
-    &= help "Default : canonical (RFC 5952)"
-  , quantity = 1
-    &= help "Amount of random addresses to generate"
-    &= typ " <Integer>"
-  , prefix = ""
-    &= typ " <Prefix>"
-    &= help "Set a prefix for random addresses generation"
-  } &= summary ("ip6addr " <> showVer <> " (c) Michel Boucey 2011-2023")
-    &= program "ip6addr"
-    &= helpArg [name "h"]
-    &= details [ "Examples:"
-               , ""
-               , "  ip6addr -a 0:0::FFFF:192.0.2.128"
-               , "  ip6addr -o full -a ::1"
-               , "  ip6addr -o random -q 10 -p 1234:abcd::"
-               , ""
-               ]
-
-showVer :: String
-showVer = "v" <> showVersion version
-
-main :: IO ()
-main = do
-  Input{..} <- cmdArgs ip6addrInput
-  if output == "random"
-    then replicateM_ quantity (putRandAddr prefix) >> exitSuccess
-    else
-      case output of
-        "canonical" -> out maybeIPv6Addr address unIPv6Addr
-        "pure"      -> out maybePureIPv6Addr address unIPv6Addr
-        "full"      -> out maybeFullIPv6Addr address unIPv6Addr
-        "arpa"      -> out maybeIP6ARPA address id
-        "unc"       -> out maybeUNC address id
-        _           -> TIO.hPutStrLn stderr "See help" >> exitFailure
-  where
-    putRandAddr p = do
-      r <- randIPv6AddrWithPrefix (if p == mempty then Nothing else Just (T.pack p))
-      case r of
-        Just a  -> TIO.putStrLn (unIPv6Addr a)
-        Nothing -> TIO.putStrLn "Bad prefix"
-    out t i o =
-      if i /= mempty
-        then do
-          let p = T.pack i
-          case t p of
-            Nothing ->
-              TIO.hPutStrLn stderr ("'" <> p <> "' is not an IPv6 address") >> exitFailure
-            Just a  -> TIO.putStrLn (o a) >> exitSuccess
-        else Prelude.putStrLn "See help" >> exitFailure
-    maybeUNC t = toUNC <$> maybePureIPv6Addr t
-    maybeIP6ARPA t = toIP6ARPA <$> maybeFullIPv6Addr t
-
diff --git a/app/ip6addr.hs b/app/ip6addr.hs
new file mode 100644
--- /dev/null
+++ b/app/ip6addr.hs
@@ -0,0 +1,148 @@
+{-# LANGUAGE OverloadedStrings   #-}
+{-# LANGUAGE RecordWildCards     #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+import           Control.Exception   (SomeException, try)
+import           Control.Monad       (replicateM_)
+import           Data.Maybe          (fromJust)
+import qualified Data.Text           as T (pack)
+import qualified Data.Text.IO        as TIO (hPutStrLn, putStr, putStrLn)
+import           Data.Version        (showVersion)
+import           Options.Applicative
+import           Paths_ip6addr       (version)
+import           System.Exit
+import           System.IO           (stderr)
+import           Text.IPv6Addr
+
+showVer :: String
+showVer = "ip6addr v"
+       <> showVersion version
+       <> " (c) Michel Boucey 2011-2024"
+
+main :: IO ()
+main = do
+  Options{..} <- execParser opts
+  if showver then failMsg $ T.pack showVer
+    else
+      case output of
+        Canonical  -> out noNewline maybeIPv6Addr address unIPv6Addr
+        NoIPv4     -> out noNewline maybePureIPv6Addr address unIPv6Addr
+        FullLength -> out noNewline maybeFullIPv6Addr address unIPv6Addr
+        PTR        -> out noNewline maybeIP6ARPA address id
+        UNC        -> out noNewline maybeUNC address id
+        Random     -> replicateM_ quantity (putRandAddr noNewline prefix) >> exitSuccess
+  where
+    putRandAddr n p = do
+      let p' = T.pack p
+      t <- try $ randIPv6AddrWithPrefix (if p == mempty then Nothing else Just p')
+      case t of
+        Right a                   -> put n (unIPv6Addr $ fromJust a)
+        Left (_ :: SomeException) -> failMsg $ "'" <> p' <> "' is an invalid prefix"
+    out n t i o =
+      if i /= mempty
+        then do
+          let p = T.pack i
+          case t p of
+            Just a  -> put n (o a) >> exitSuccess
+            Nothing -> failMsg $ "'" <> p <> "' is not an IPv6 address"
+        else failMsg "See --help"
+    maybeUNC t = toUNC <$> maybePureIPv6Addr t
+    maybeIP6ARPA t = toIP6ARPA <$> maybeFullIPv6Addr t
+    put n = if n then TIO.putStr else TIO.putStrLn
+    failMsg m = TIO.hPutStrLn stderr m >> exitFailure
+
+data Output
+  = Canonical
+  | NoIPv4
+  | FullLength
+  | PTR
+  | UNC
+  | Random
+  deriving (Eq)
+
+data Options =
+  Options
+    { showver   :: !Bool
+    , output    :: !Output
+    , quantity  :: !Int
+    , prefix    :: !String
+    , noNewline :: !Bool
+    , address   :: !String
+    }
+
+opts :: ParserInfo Options
+opts = info (parseOptions <**> helper)
+  ( fullDesc
+    <> progDesc "ip6addr"
+    <> header showVer
+  )
+
+parseOptions :: Parser Options
+parseOptions =
+  Options
+    <$>
+      switch
+        ( short 'v'
+          <> long "version"
+          <> help "Show version"
+        )
+    <*>
+      (flag Canonical Canonical
+        ( short 'c'
+          <> long "canonical"
+          <> help "In conformation with RFC 5952 (default output)"
+        )
+   <|>
+      flag' NoIPv4
+        ( short 'n'
+          <> long "no-ipv4"
+          <> help "Force the rewriting of the IPv4 address if present\
+                   \ to get a pure IPv6 address made of nibbles only"
+        )
+   <|>
+      flag' FullLength
+        ( short 'f'
+          <> long "full-length"
+          <> help "Full IPv6 address length"
+        )
+   <|>
+      flag' PTR
+        ( short 'p'
+          <> long "ptr"
+          <> help "PTR reverse mapping"
+        )
+   <|>
+      flag' UNC
+        ( short 'w'
+          <> long "windows-unc"
+          <> help "Windows UNC path name"
+        )
+   <|>
+      flag' Random
+        ( short 'r'
+          <> long "random"
+          <> help "Random generation"
+        )
+     )
+   <*>
+      option auto
+        ( short 'q'
+          <> long "quantity"
+          <> help "Amount of random addresses to generate"
+          <> value 1
+        )
+   <*>
+      option str
+        ( short 's'
+          <> long "prefix"
+          <> help "Set a prefix for random addresses to generate"
+          <> value ""
+        )
+   <*>
+      flag False True
+        ( short 'd'
+          <> long "no-newline"
+          <> help "Do not output trailing newlines" )
+   <*>
+      argument str (metavar "IPv6 address" <> value "")
+
diff --git a/ip6addr.cabal b/ip6addr.cabal
--- a/ip6addr.cabal
+++ b/ip6addr.cabal
@@ -1,5 +1,5 @@
 name:                ip6addr
-version:             1.0.4
+version:             2.0.0
 synopsis:            Commandline tool to deal with IPv6 address text representations
 description:         Commandline tool to validate, canonize and generate IPv6 address text representations
 license:             BSD3
@@ -13,7 +13,7 @@
 cabal-version:       >=1.10
 extra-source-files:  README.md
  
-Tested-With: GHC ==8.8.4 || ==8.10.7 || ==9.0.2 || ==9.2.8 || ==9.4.8 || ==9.6.3 || ==9.8.1
+Tested-With: GHC ==8.8.4 || ==8.10.7 || ==9.0.2 || ==9.2.8 || ==9.4.8 || ==9.6.3 || ==9.8.2
 
 Source-Repository head
   Type: git
@@ -21,14 +21,14 @@
 
 executable ip6addr
   hs-source-dirs:      app
-  main-is:             Main.hs
+  main-is:             ip6addr.hs
   other-modules:       Paths_ip6addr
   other-extensions:    DeriveDataTypeable
                      , OverloadedStrings
-  build-depends:       base             >= 4.8 && < 5
-                     , cmdargs          >= 0.10.13 && < 0.11
-                     , IPv6Addr         >= 2.0.0 && < 2.1
-                     , text             >=1.1 && < 2.2
+  build-depends:       base                 >= 4.8 && < 5
+                     , IPv6Addr             >= 2.0.0 && < 2.1
+                     , optparse-applicative >= 0.14 && < 0.19
+                     , text                 >=1.1 && < 2.2
   default-language:    Haskell2010
   GHC-Options:         -Wall
 
