{-# LANGUAGE OverloadedStrings
, TupleSections
, StandaloneDeriving #-}
module System.Posix.ARX.CLI.Options where
import Control.Applicative hiding (many)
import Control.Monad
import Data.ByteString (ByteString)
import qualified Data.ByteString as Bytes
import qualified Data.ByteString.Char8 as Char8
import Data.Either
import Data.List
import Data.Maybe
import Data.Ord
import Data.Word
import Text.Parsec hiding (satisfy, (<|>))
import qualified Data.Attoparsec.ByteString as Attoparsec
import System.Posix.ARX.CLI.CLTokens (Class(..))
import qualified System.Posix.ARX.CLI.CLTokens as CLTokens
import qualified System.Posix.ARX.Sh as Sh
shdat :: ArgsParser ([Word], [IOStream], [IOStream])
shdat = do
arg "shdat"
coalesce <$> manyTill (_1 blockSize <|> _2 outputFile <|> _3 ioStream) eof
where
_1 = ((,Nothing,Nothing) . Just <$>)
_2 = ((Nothing,,Nothing) . Just <$>)
_3 = ((Nothing,Nothing,) . Just <$>)
coalesce = foldr f ([], [], [])
where
f (Just a, _, _) (as, bs, cs) = (a:as, bs, cs)
f (_, Just b, _) (as, bs, cs) = (as, b:bs, cs)
f (_, _, Just c) (as, bs, cs) = (as, bs, c:cs)
f _ stuff = stuff
tmpx :: ArgsParser ( [Word], [IOStream], [IOStream], [(Sh.Var, Sh.Val)],
[ByteString], [(Bool, Bool)], [Bool], [ByteSource] )
tmpx = do
arg "tmpx"
bars <- (try . lookAhead) slashes
coalesce <$> case bars of
Nothing -> flags eof
Just bars -> do let eof_bars = () <$ arg bars <|> eof
before <- flags eof_bars
cmd <- _8 (gather eof_bars)
after <- flags eof
return (before ++ (cmd:after))
where
flags = manyTill flag
gather = (ByteString . Char8.unwords <$>) . manyTill anyArg
flag = _1 blockSize <|> _2 outputFile <|> _3 ioStream
<|> _4 env <|> _5 tmpdir <|> _6 rm
<|> _7 shared <|> _8 scriptToRun
_1 = ((,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing) . Just <$>)
_2 = ((Nothing,,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing) . Just <$>)
_3 = ((Nothing,Nothing,,Nothing,Nothing,Nothing,Nothing,Nothing) . Just <$>)
_4 = ((Nothing,Nothing,Nothing,,Nothing,Nothing,Nothing,Nothing) . Just <$>)
_5 = ((Nothing,Nothing,Nothing,Nothing,,Nothing,Nothing,Nothing) . Just <$>)
_6 = ((Nothing,Nothing,Nothing,Nothing,Nothing,,Nothing,Nothing) . Just <$>)
_7 = ((Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,,Nothing) . Just <$>)
_8 = ((Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,Nothing,) . Just <$>)
coalesce = foldr f ([], [], [], [], [], [], [], [])
where
f (Just a, _, _, _, _, _, _, _) (as, bs, cs, ds, es, fs, gs, hs)
= (a:as, bs, cs, ds, es, fs, gs, hs)
f (_, Just b, _, _, _, _, _, _) (as, bs, cs, ds, es, fs, gs, hs)
= (as, b:bs, cs, ds, es, fs, gs, hs)
f (_, _, Just c, _, _, _, _, _) (as, bs, cs, ds, es, fs, gs, hs)
= (as, bs, c:cs, ds, es, fs, gs, hs)
f (_, _, _, Just d, _, _, _, _) (as, bs, cs, ds, es, fs, gs, hs)
= (as, bs, cs, d:ds, es, fs, gs, hs)
f (_, _, _, _, Just e, _, _, _) (as, bs, cs, ds, es, fs, gs, hs)
= (as, bs, cs, ds, e:es, fs, gs, hs)
f (_, _, _, _, _, Just f, _, _) (as, bs, cs, ds, es, fs, gs, hs)
= (as, bs, cs, ds, es, f:fs, gs, hs)
f (_, _, _, _, _, _, Just g, _) (as, bs, cs, ds, es, fs, gs, hs)
= (as, bs, cs, ds, es, fs, g:gs, hs)
f (_, _, _, _, _, _, _, Just h) (as, bs, cs, ds, es, fs, gs, hs)
= (as, bs, cs, ds, es, fs, gs, h:hs)
f _ stuff = stuff
blockSize :: ArgsParser Word
blockSize = do arg "-b"
CLTokens.sizeBounded <@> tokCL Size
outputFile :: ArgsParser IOStream
outputFile = arg "-o" >> ioStream
ioStream :: ArgsParser IOStream
ioStream = STDIO <$ tokCL Dash
<|> Path <$> tokCL QualifiedPath
qPath :: ArgsParser ByteString
qPath = tokCL QualifiedPath
shared :: ArgsParser Bool
shared = True <$ arg "--shared"
tmpdir :: ArgsParser ByteString
tmpdir = arg "--tmpdir" >> tokCL QualifiedPath
rm :: ArgsParser (Bool, Bool)
rm = (True, False) <$ arg "-rm0" <|> (False, True) <$ arg "-rm1"
<|> (False, False) <$ arg "-rm!" <|> (True, True) <$ arg "-rm_"
env :: ArgsParser (Sh.Var, Sh.Val)
env = do
(var, assignment) <- Char8.break (== '=') <$> tokCL EnvBinding
case (,) <$> Sh.var var <*> Sh.val (Bytes.drop 1 assignment) of
Nothing -> mzero
Just x -> return x
scriptToRun :: ArgsParser ByteSource
scriptToRun = arg "-e" >> IOStream <$> ioStream
cmd :: ByteString -> ArgsParser ByteSource
cmd bars = ByteString . Char8.unwords <$> bracketed bars bars anyArg
where
bracketed start end p = arg start >> manyTill p (eof <|> () <$ arg end)
data IOStream = STDIO | Path !ByteString
deriving instance Eq IOStream
deriving instance Ord IOStream
deriving instance Show IOStream
data ByteSource = ByteString !ByteString | IOStream !IOStream
deriving instance Eq ByteSource
deriving instance Ord ByteSource
deriving instance Show ByteSource
type ArgsParser = Parsec [ByteString] ()
satisfy :: (ByteString -> Bool) -> ArgsParser ByteString
satisfy p = argPrim test
where
test b = guard (p b) >> Just b
anyArg :: ArgsParser ByteString
anyArg = argPrim Just
arg :: ByteString -> ArgsParser ByteString
arg b = satisfy (== b)
argPrim :: (ByteString -> Maybe t) -> ArgsParser t
argPrim = tokenPrim show next
where
next pos _ _ = incSourceLine pos 1
(<@>) :: Attoparsec.Parser t -> ArgsParser ByteString -> ArgsParser t
atto <@> parsec = do
res <- Attoparsec.parseOnly atto <$> parsec
case res of Left _ -> mzero
Right x -> return x
infixl 4 <@>
tokCL :: Class -> ArgsParser ByteString
tokCL tokenClass = satisfy (CLTokens.match tokenClass)
slashes :: ArgsParser (Maybe ByteString)
slashes = listToMaybe . longestFirst . catMaybes <$> manyTill classify eof
where
classify = Just <$> satisfy slashRun <|> Nothing <$ anyArg
longestFirst = sortBy (comparing (negate . Bytes.length))
slashRun s = Char8.all (== '/') s && Bytes.length s > 1