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