module CLI ( parse ) where import Config import Options.Applicative import Control.Monad.IO.Class import qualified StreamPatch.Patch.Binary as Bin parse :: MonadIO m => m Config parse = execParserWithDefaults desc pConfig where desc = "Patch bytestrings (TODO)." pConfig :: Parser Config pConfig = Config <$> strArgument (metavar "PATCHSCRIPT" <> help "Path to patchscript") <*> pCStreamPair <*> pCPatchFormat <*> pPrintBinary pCStreamPair :: Parser CStreamPair pCStreamPair = CStreamPair <$> pCSIn <*> pCSOut where pCSIn = pFileArg <|> pStdin pCSOut = pFileOpt <|> pure CStreamStd pFileArg = CStreamFile <$> strArgument (metavar "FILE" <> help "Input file") pFileOpt = CStreamFile <$> strOption (metavar "FILE" <> long "out-file" <> short 'o' <> help "Output file") pStdin = flag' CStreamStd (long "stdin" <> help "Use stdin") pCPatchFormat :: Parser CPatchFormat pCPatchFormat = CPatchFormat <$> pCPatchDataType <*> pCPatchAlign <*> pBinCfg pCPatchDataType :: Parser CPatchDataType pCPatchDataType = option (maybeReader mapper) $ long "type" <> short 't' <> help "How to interpret & use patch data (binary/text/text-only)" <> metavar "PATCH_TYPE" where mapper = \case "text-only" -> Just CTextPatch "bin" -> Just CBinPatch "binary" -> Just CBinPatch "text" -> Just CTextBinPatch _ -> Nothing pCPatchAlign :: Parser CPatchAlign pCPatchAlign = flag CNoAlignPatch CAlignPatch $ long "aligned" <> help "Parse alignment data" pBinCfg :: Parser Bin.Cfg pBinCfg = Bin.Cfg <$> pExactMatch where pExactMatch = flag True False $ long "match-exact" <> help "Expected binary data must match exactly (rather than be a prefix)" pPrintBinary :: Parser Bool pPrintBinary = switch $ long "print-binary" <> help "Force print binary to stdout" -------------------------------------------------------------------------------- -- | Execute a 'Parser' with decent defaults. execParserWithDefaults :: MonadIO m => String -> Parser a -> m a execParserWithDefaults desc p = liftIO $ customExecParser (prefs $ showHelpOnError) (info (helper <*> p) (progDesc desc))