{-# LANGUAGE RecordWildCards #-} module System.Console.CmdArgs.Explicit.SplitJoin(splitArgs, joinArgs) where import Data.Char import Data.Maybe -- | Given a sequence of arguments, join them together in a manner that could be used on -- the command line, giving preference to the Windows @cmd@ shell quoting conventions. -- -- For an alternative version, intended for actual running the result in a shell, see "System.Process.showCommandForUser" joinArgs :: [String] -> String joinArgs = unwords . map f where f x = q ++ g x ++ q where hasSpace = any isSpace x q = ['\"' | hasSpace || null x] g ('\\':'\"':xs) = '\\':'\\':'\\':'\"': g xs g "\\" | hasSpace = "\\\\" g ('\"':xs) = '\\':'\"': g xs g (x:xs) = x : g xs g [] = [] data State = Init -- either I just started, or just emitted something | Norm -- I'm seeing characters | Quot -- I've seen a quote -- | Given a string, split into the available arguments. The inverse of 'joinArgs'. splitArgs :: String -> [String] splitArgs = join . f Init where -- Nothing is start a new string -- Just x is accumulate onto the existing string join :: [Maybe Char] -> [String] join [] = [] join xs = map fromJust a : join (drop 1 b) where (a,b) = break isNothing xs f Init (x:xs) | isSpace x = f Init xs f Init "\"\"" = [Nothing] f Init "\"" = [Nothing] f Init xs = f Norm xs f m ('\"':'\"':'\"':xs) = Just '\"' : f m xs f m ('\\':'\"':xs) = Just '\"' : f m xs f m ('\\':'\\':'\"':xs) = Just '\\' : f m ('\"':xs) f Norm ('\"':xs) = f Quot xs f Quot ('\"':'\"':xs) = Just '\"' : f Norm xs f Quot ('\"':xs) = f Norm xs f Norm (x:xs) | isSpace x = Nothing : f Init xs f m (x:xs) = Just x : f m xs f m [] = []