1{-# LANGUAGE RecordWildCards #-} 2module System.Console.CmdArgs.Explicit.SplitJoin(splitArgs, joinArgs) where 3 4import Data.Char 5import Data.Maybe 6 7 8-- | Given a sequence of arguments, join them together in a manner that could be used on 9-- the command line, giving preference to the Windows @cmd@ shell quoting conventions. 10-- 11-- For an alternative version, intended for actual running the result in a shell, see "System.Process.showCommandForUser" 12joinArgs :: [String] -> String 13joinArgs = unwords . map f 14 where 15 f x = q ++ g x ++ q 16 where 17 hasSpace = any isSpace x 18 q = ['\"' | hasSpace || null x] 19 20 g ('\\':'\"':xs) = '\\':'\\':'\\':'\"': g xs 21 g "\\" | hasSpace = "\\\\" 22 g ('\"':xs) = '\\':'\"': g xs 23 g (x:xs) = x : g xs 24 g [] = [] 25 26 27data State = Init -- either I just started, or just emitted something 28 | Norm -- I'm seeing characters 29 | Quot -- I've seen a quote 30 31-- | Given a string, split into the available arguments. The inverse of 'joinArgs'. 32splitArgs :: String -> [String] 33splitArgs = join . f Init 34 where 35 -- Nothing is start a new string 36 -- Just x is accumulate onto the existing string 37 join :: [Maybe Char] -> [String] 38 join [] = [] 39 join xs = map fromJust a : join (drop 1 b) 40 where (a,b) = break isNothing xs 41 42 f Init (x:xs) | isSpace x = f Init xs 43 f Init "\"\"" = [Nothing] 44 f Init "\"" = [Nothing] 45 f Init xs = f Norm xs 46 f m ('\"':'\"':'\"':xs) = Just '\"' : f m xs 47 f m ('\\':'\"':xs) = Just '\"' : f m xs 48 f m ('\\':'\\':'\"':xs) = Just '\\' : f m ('\"':xs) 49 f Norm ('\"':xs) = f Quot xs 50 f Quot ('\"':'\"':xs) = Just '\"' : f Norm xs 51 f Quot ('\"':xs) = f Norm xs 52 f Norm (x:xs) | isSpace x = Nothing : f Init xs 53 f m (x:xs) = Just x : f m xs 54 f m [] = [] 55