[commit: base] encoding: Retrieve command line arguments on Windows using wide API (c6f7952)
Ian Lynagh
igloo at earth.li
Wed Apr 6 23:38:18 CEST 2011
Repository : ssh://darcs.haskell.org//srv/darcs/packages/base
On branch : encoding
http://hackage.haskell.org/trac/ghc/changeset/c6f795239b313befdf9b9a7df356ae0b81d6ea1b
>---------------------------------------------------------------
commit c6f795239b313befdf9b9a7df356ae0b81d6ea1b
Author: Max Bolingbroke <batterseapower at hotmail.com>
Date: Tue Apr 5 12:55:00 2011 +0100
Retrieve command line arguments on Windows using wide API
>---------------------------------------------------------------
GHC/Environment.hs | 28 ++++++++++++++++++-
System/Environment.hs | 69 +++++++++++++++++++++++++++++++++++-------------
2 files changed, 76 insertions(+), 21 deletions(-)
diff --git a/GHC/Environment.hs b/GHC/Environment.hs
index df1d59d..4bdd4c1 100644
--- a/GHC/Environment.hs
+++ b/GHC/Environment.hs
@@ -10,6 +10,31 @@ import Control.Monad
import GHC.IO.Encoding
import qualified GHC.Foreign as GHC
+#ifdef mingw32_HOST_OS
+import GHC.Windows
+
+-- Ignore the arguments to hs_init on Windows for the sake of Unicode compat
+getFullArgs :: IO [String]
+getFullArgs = do
+ p_arg_string <- c_GetCommandLine
+ alloca $ \p_argc -> do
+ p_argv <- c_CommandLineToArgv p_arg_string p_argc
+ if p_argv == nullPtr
+ then throwGetLastError "getFullArgs"
+ else flip finally (c_LocalFree p_argv) $ do
+ argc <- peek p_argc
+ p_argvs <- peekArray (fromIntegral argc) p_argv
+ mapM peekCWString p_argvs
+
+foreign import stdcall unsafe "windows.h GetCommandLineW"
+ c_GetCommandLine :: IO (Ptr CWString)
+
+foreign import stdcall unsafe "windows.h CommandLineToArgvW"
+ c_CommandLineToArgv :: Ptr CWString -> Ptr CInt -> IO (Ptr (Ptr CWString))
+
+foreign import stdcall unsafe "Windows.h LocalFree"
+ c_LocalFree :: Ptr a -> Ptr a
+#else
getFullArgs :: IO [String]
getFullArgs =
alloca $ \ p_argc ->
@@ -17,9 +42,8 @@ getFullArgs =
getFullProgArgv p_argc p_argv
p <- fromIntegral `liftM` peek p_argc
argv <- peek p_argv
- -- FIXME: we should use GetCommandLineW on Windows instead
peekArray (p - 1) (advancePtr argv 1) >>= mapM (GHC.peekCString fileSystemEncoding)
foreign import ccall unsafe "getFullProgArgv"
getFullProgArgv :: Ptr CInt -> Ptr (Ptr CString) -> IO ()
-
+#endif
\ No newline at end of file
diff --git a/System/Environment.hs b/System/Environment.hs
index 67ad1ef..0fd0d3b 100644
--- a/System/Environment.hs
+++ b/System/Environment.hs
@@ -41,7 +41,10 @@ import GHC.IO.Exception
import GHC.IO.Encoding (fileSystemEncoding)
import qualified GHC.Foreign as GHC
#ifdef mingw32_HOST_OS
+import GHC.Environment
import GHC.Windows
+import Data.IORef
+import System.IO.Unsafe
#endif
#endif
@@ -57,26 +60,46 @@ import System
)
#endif
+#ifdef __GLASGOW_HASKELL__
-- ---------------------------------------------------------------------------
-- getArgs, getProgName, getEnv
+#ifdef mingw32_HOST_OS
+
+{-# NOINLINE argsRef #-}
+argsRef :: IORef [String]
+argsRef = unsafePerformIO $ do
+ -- Ignore the arguments to hs_init on Windows for the sake of Unicode compat
+ init_args <- fmap (dropRTSArgs . drop 1) getFullArgs
+ newIORef init_args
+
+dropRTSArgs :: [String] -> [String]
+dropRTSArgs [] = []
+dropRTSArgs ("+RTS":rest) = dropRTSArgs (dropWhile (/= "-RTS") rest)
+dropRTSArgs ("--RTS":rest) = rest
+dropRTSArgs ("-RTS":rest) = dropRTSArgs rest
+dropRTSArgs (arg:rest) = arg : dropRTSArgs rest
+
+#endif
+
-- | Computation 'getArgs' returns a list of the program's command
-- line arguments (not including the program name).
-
-#ifdef __GLASGOW_HASKELL__
getArgs :: IO [String]
+
+#ifdef mingw32_HOST_OS
+getArgs = readIORef argsRef
+#else
getArgs =
alloca $ \ p_argc ->
alloca $ \ p_argv -> do
getProgArgv p_argc p_argv
p <- fromIntegral `liftM` peek p_argc
argv <- peek p_argv
- -- FIXME: we should use GetCommandLineW on Windows instead
peekArray (p - 1) (advancePtr argv 1) >>= mapM (GHC.peekCString fileSystemEncoding)
-
foreign import ccall unsafe "getProgArgv"
getProgArgv :: Ptr CInt -> Ptr (Ptr CString) -> IO ()
+#endif
{-|
Computation 'getProgName' returns the name of the program as it was
@@ -89,6 +112,10 @@ between platforms: on Windows, for example, a program invoked as foo
is probably really @FOO.EXE@, and that is what 'getProgName' will return.
-}
getProgName :: IO String
+#ifdef mingw32_HOST_OS
+-- Ignore the arguments to hs_init on Windows for the sake of Unicode compat
+getProgName = fmap (basename . head) getFullArgs
+#else
getProgName =
alloca $ \ p_argc ->
alloca $ \ p_argv -> do
@@ -98,24 +125,24 @@ getProgName =
unpackProgName :: Ptr (Ptr CChar) -> IO String -- argv[0]
unpackProgName argv = do
- -- FIXME: we should use GetCommandLineW on Windows instead
s <- peekElemOff argv 0 >>= GHC.peekCString fileSystemEncoding
return (basename s)
- where
- basename :: String -> String
- basename f = go f f
- where
- go acc [] = acc
- go acc (x:xs)
- | isPathSeparator x = go xs xs
- | otherwise = go acc xs
-
- isPathSeparator :: Char -> Bool
- isPathSeparator '/' = True
+#endif
+
+basename :: FilePath -> FilePath
+basename f = go f f
+ where
+ go acc [] = acc
+ go acc (x:xs)
+ | isPathSeparator x = go xs xs
+ | otherwise = go acc xs
+
+ isPathSeparator :: Char -> Bool
+ isPathSeparator '/' = True
#ifdef mingw32_HOST_OS
- isPathSeparator '\\' = True
+ isPathSeparator '\\' = True
#endif
- isPathSeparator _ = False
+ isPathSeparator _ = False
-- | Computation 'getEnv' @var@ returns the value
@@ -191,14 +218,18 @@ freeArgv argv = do
free argv
setArgs :: [String] -> IO (Ptr CString)
+
+#ifdef mingw32_HOST_OS
+setArgs argv = atomicModifyIORef argsRef $ \_ -> (argv, ())
+#else
setArgs argv = do
- -- FIXME: do something else on Windows instead...
vs <- mapM (GHC.newCString fileSystemEncoding) argv >>= newArray0 nullPtr
setArgsPrim (genericLength argv) vs
return vs
foreign import ccall unsafe "setProgArgv"
setArgsPrim :: CInt -> Ptr CString -> IO ()
+#endif
-- |'getEnvironment' retrieves the entire environment as a
-- list of @(key,value)@ pairs.
More information about the Cvs-libraries
mailing list