|
1 | 1 | #if __GLASGOW_HASKELL__ >= 709
|
2 |
| -{-# LANGUAGE Safe #-} |
| 2 | +{-# LANGUAGE Trustworthy #-} |
3 | 3 | #else
|
4 | 4 | {-# LANGUAGE Trustworthy #-}
|
5 | 5 | #endif
|
@@ -56,22 +56,31 @@ module System.Win32.Console (
|
56 | 56 | getConsoleScreenBufferInfo,
|
57 | 57 | getCurrentConsoleScreenBufferInfo,
|
58 | 58 | getConsoleScreenBufferInfoEx,
|
59 |
| - getCurrentConsoleScreenBufferInfoEx |
| 59 | + getCurrentConsoleScreenBufferInfoEx, |
| 60 | + |
| 61 | + -- * Env |
| 62 | + getEnv, |
| 63 | + getEnvironment |
60 | 64 | ) where
|
61 | 65 |
|
62 | 66 | #include <windows.h>
|
63 | 67 | #include "alignment.h"
|
64 | 68 | ##include "windows_cconv.h"
|
65 | 69 | #include "wincon_compat.h"
|
66 | 70 |
|
| 71 | +import Data.Char (chr) |
67 | 72 | import System.Win32.Types
|
| 73 | +import System.Win32.String |
68 | 74 | import System.Win32.Console.Internal
|
69 | 75 | import Graphics.Win32.Misc
|
70 | 76 | import Graphics.Win32.GDI.Types (COLORREF)
|
71 | 77 |
|
72 |
| -import Foreign.C.String (withCWString) |
| 78 | +import GHC.IO (bracket) |
| 79 | +import Foreign.Ptr (plusPtr) |
| 80 | +import Foreign.C.Types (CWchar) |
| 81 | +import Foreign.C.String (withCWString, CWString) |
73 | 82 | import Foreign.Storable (Storable(..))
|
74 |
| -import Foreign.Marshal.Array (peekArray) |
| 83 | +import Foreign.Marshal.Array (peekArray, peekArray0) |
75 | 84 | import Foreign.Marshal.Alloc (alloca)
|
76 | 85 |
|
77 | 86 |
|
@@ -154,3 +163,65 @@ getCurrentConsoleScreenBufferInfoEx :: IO CONSOLE_SCREEN_BUFFER_INFOEX
|
154 | 163 | getCurrentConsoleScreenBufferInfoEx = do
|
155 | 164 | h <- failIf (== nullHANDLE) "getStdHandle" $ getStdHandle sTD_OUTPUT_HANDLE
|
156 | 165 | getConsoleScreenBufferInfoEx h
|
| 166 | + |
| 167 | + |
| 168 | +-- c_GetEnvironmentVariableW :: LPCWSTR -> LPWSTR -> DWORD -> IO DWORD |
| 169 | +getEnv :: String -> IO (Maybe String) |
| 170 | +getEnv name = |
| 171 | + withCWString name $ \c_name -> withTStringBufferLen maxLength $ \(buf, len) -> do |
| 172 | + let c_len = fromIntegral len |
| 173 | + c_len' <- c_GetEnvironmentVariableW c_name buf c_len |
| 174 | + if c_len' == 0 |
| 175 | + then do |
| 176 | + err_code <- getLastError |
| 177 | + if err_code == eERROR_ENVVAR_NOT_FOUND |
| 178 | + then return Nothing |
| 179 | + else errorWin "GetEnvironmentVariableW" |
| 180 | + else do |
| 181 | + let len' = fromIntegral c_len' |
| 182 | + Just <$> peekTStringLen (buf, len') |
| 183 | + where |
| 184 | + -- according to https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-getenvironmentvariablew |
| 185 | + maxLength :: Int |
| 186 | + maxLength = 32767 |
| 187 | + |
| 188 | + |
| 189 | +getEnvironment :: IO [(String, String)] |
| 190 | +getEnvironment = bracket c_GetEnvironmentStringsW c_FreeEnvironmentStrings $ \lpwstr -> do |
| 191 | + strs <- builder lpwstr |
| 192 | + return (divvy <$> strs) |
| 193 | + where |
| 194 | + divvy :: String -> (String, String) |
| 195 | + divvy str = |
| 196 | + case break (=='=') str of |
| 197 | + (xs,[]) -> (xs,[]) -- don't barf (like Posix.getEnvironment) |
| 198 | + (name,_:value) -> (name,value) |
| 199 | + |
| 200 | + builder :: LPWSTR -> IO [String] |
| 201 | + builder ptr = go 0 |
| 202 | + where |
| 203 | + go :: Int -> IO [String] |
| 204 | + go off = do |
| 205 | + (str, l) <- peekCWStringOff ptr off |
| 206 | + if l == 0 |
| 207 | + then pure [] |
| 208 | + else (str:) <$> go (((l + 1) * 2) + off) |
| 209 | + |
| 210 | + |
| 211 | +peekCWStringOff :: CWString -> Int -> IO (String, Int) |
| 212 | +peekCWStringOff cp off = do |
| 213 | + cs <- peekArray0 wNUL (cp `plusPtr` off) |
| 214 | + return (cWcharsToChars cs, length cs) |
| 215 | + |
| 216 | +wNUL :: CWchar |
| 217 | +wNUL = 0 |
| 218 | + |
| 219 | +cWcharsToChars :: [CWchar] -> [Char] |
| 220 | +cWcharsToChars = map chr . fromUTF16 . map fromIntegral |
| 221 | + where |
| 222 | + fromUTF16 (c1:c2:wcs) |
| 223 | + | 0xd800 <= c1 && c1 <= 0xdbff && 0xdc00 <= c2 && c2 <= 0xdfff = |
| 224 | + ((c1 - 0xd800)*0x400 + (c2 - 0xdc00) + 0x10000) : fromUTF16 wcs |
| 225 | + fromUTF16 (c:wcs) = c : fromUTF16 wcs |
| 226 | + fromUTF16 [] = [] |
| 227 | + |
0 commit comments