aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn MacFarlane <[email protected]>2023-07-19 10:56:35 -0700
committerJohn MacFarlane <[email protected]>2023-07-19 11:56:58 -0700
commitbec5429e4f7180af135cabc2dc79b82a406a357d (patch)
tree6d15a1e8c31931a57347881818b895ce2ad00b79 /src
parent5b2128512df61085c4a0ae364030482f21626dc6 (diff)
Fix regression on short boolean arguments.
In 3.1.5 boolean arguments were allowed an optional argument (true|false). This created a regression for uses of fused short arguments, e.g. `-somyfile.html`, which was equivalent to `-s -omyfile.html`, but now raised an error because pandoc attempted to parse `o` as a boolean `true` or `false`. This change adds a preprocessing step on the raw arguments before they are sent to the option parser. In this preprocessing step, `-somyfile.html` would be split into two arguments, `-s` and `-omyfile.html`. The splitting happens when a short boolean option is followed by another short option. Closes #8956.
Diffstat (limited to 'src')
-rw-r--r--src/Text/Pandoc/App/CommandLineOptions.hs36
1 files changed, 34 insertions, 2 deletions
diff --git a/src/Text/Pandoc/App/CommandLineOptions.hs b/src/Text/Pandoc/App/CommandLineOptions.hs
index a4374478f..22e824ade 100644
--- a/src/Text/Pandoc/App/CommandLineOptions.hs
+++ b/src/Text/Pandoc/App/CommandLineOptions.hs
@@ -59,13 +59,14 @@ import Control.Monad.Except (ExceptT(..), runExceptT, throwError)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as B
import qualified Data.Map as M
+import qualified Data.Set as Set
import qualified Data.Text as T
import qualified Text.Pandoc.UTF8 as UTF8
parseOptions :: [OptDescr (Opt -> ExceptT OptInfo IO Opt)]
-> Opt -> IO (Either OptInfo Opt)
parseOptions options' defaults = do
- rawArgs <- map UTF8.decodeArg <$> liftIO getArgs
+ rawArgs <- liftIO getArgs
prg <- liftIO getProgName
parseOptionsFromArgs options' defaults prg rawArgs
@@ -74,7 +75,7 @@ parseOptionsFromArgs
-> Opt -> String -> [String] -> IO (Either OptInfo Opt)
parseOptionsFromArgs options' defaults prg rawArgs = do
let (actions, args, unrecognizedOpts, errors) =
- getOpt' Permute options' (map UTF8.decodeArg rawArgs)
+ getOpt' Permute options' (preprocessArgs rawArgs)
let unknownOptionErrors =
foldr (handleUnrecognizedOption . takeWhile (/= '=')) []
@@ -230,6 +231,37 @@ engines = map ("html",) htmlEngines ++
pdfEngines :: [String]
pdfEngines = nubOrd $ map snd engines
+-- For motivation see #8956. We want to allow things like `-si` without
+-- causing the `i` to be parsed as an optional boolean argument of `-s`.
+-- This is for backwards compatibility given the addition of optional
+-- boolean arguments in #8879.
+preprocessArgs :: [String] -> [String]
+preprocessArgs [] = []
+preprocessArgs ("--":xs) = "--" : xs -- a bare '--' ends option parsing
+preprocessArgs (('-':c:d:cs):xs)
+ | isShortBooleanOpt c
+ , isShortOpt d = splitArg (c:d:cs) ++ preprocessArgs xs
+preprocessArgs (x:xs) = x : preprocessArgs xs
+
+isShortBooleanOpt :: Char -> Bool
+isShortBooleanOpt = (`Set.member` shortBooleanOpts)
+ where
+ shortBooleanOpts =
+ Set.fromList [c | Option [c] _ (OptArg _ "true|false") _ <- options]
+
+isShortOpt :: Char -> Bool
+isShortOpt = (`Set.member` shortOpts)
+ where
+ shortOpts = Set.fromList $ concat [cs | Option cs _ _ _ <- options]
+
+splitArg :: String -> [String]
+splitArg (c:d:cs)
+ | isShortBooleanOpt c
+ , isShortOpt d
+ = ['-',c] : splitArg (d:cs)
+splitArg (c:cs) = ['-':c:cs]
+splitArg [] = []
+
-- | A list of functions, each transforming the options data structure
-- in response to a command-line option.
options :: [OptDescr (Opt -> ExceptT OptInfo IO Opt)]