diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Environment.hs | 61 | ||||
-rw-r--r-- | src/Registry.hs | 133 | ||||
-rw-r--r-- | src/Utils.hs | 24 |
3 files changed, 112 insertions, 106 deletions
diff --git a/src/Environment.hs b/src/Environment.hs index 0690278..2b53258 100644 --- a/src/Environment.hs +++ b/src/Environment.hs @@ -4,29 +4,32 @@ - See LICENSE.txt for details. -} -module Environment ( saveToRegistry - , saveToRegistryWithPrompt - , queryFromRegistry - , wipeFromRegistry - , wipeFromRegistryWithPrompt - , getEnv - , splitPaths - , joinPaths - , RegistryBasedEnvironment(..) ) where - -import Control.Monad ( liftM, when ) -import Data.List ( intercalate ) -import Data.List.Split ( splitOn ) -import Data.Maybe ( fromMaybe ) -import qualified System.Environment ( lookupEnv ) -import System.IO.Error ( catchIOError, isDoesNotExistError ) +module Environment + ( saveToRegistry + , saveToRegistryWithPrompt + , queryFromRegistry + , wipeFromRegistry + , wipeFromRegistryWithPrompt + , getEnv + , splitPaths + , joinPaths + , RegistryBasedEnvironment(..) + ) where + +import Control.Monad (liftM, when) +import Data.List (intercalate) +import Data.List.Split (splitOn) +import Data.Maybe (fromMaybe) +import qualified System.Environment (lookupEnv) +import System.IO.Error (catchIOError, isDoesNotExistError) import qualified Registry -import qualified Utils ( promptToContinue ) +import qualified Utils (promptToContinue) -data RegistryBasedEnvironment = CurrentUserEnvironment - | AllUsersEnvironment - deriving (Eq, Show) +data RegistryBasedEnvironment + = CurrentUserEnvironment + | AllUsersEnvironment + deriving (Eq, Show) registrySubKeyPath :: RegistryBasedEnvironment -> String registrySubKeyPath CurrentUserEnvironment = "Environment" @@ -45,12 +48,12 @@ saveToRegistry env = Registry.setString (registryKey env) (registrySubKeyPath en saveToRegistryWithPrompt :: RegistryBasedEnvironment -> String -> String -> IO () saveToRegistryWithPrompt env name value = do - putStrLn $ "Saving variable '" ++ name ++ "' to '" ++ registryKeyPath env ++ "'..." - oldValue <- queryFromRegistry env name - putStrLn $ "\tOld value: " ++ oldValue - putStrLn $ "\tNew value: " ++ value - agreed <- Utils.promptToContinue - when agreed $ saveToRegistry env name value + putStrLn $ "Saving variable '" ++ name ++ "' to '" ++ registryKeyPath env ++ "'..." + oldValue <- queryFromRegistry env name + putStrLn $ "\tOld value: " ++ oldValue + putStrLn $ "\tNew value: " ++ value + agreed <- Utils.promptToContinue + when agreed $ saveToRegistry env name value queryFromRegistry :: RegistryBasedEnvironment -> String -> IO String queryFromRegistry env name = catchIOError (Registry.getString (registryKey env) (registrySubKeyPath env) name) emptyIfDoesNotExist @@ -66,9 +69,9 @@ wipeFromRegistry env name = catchIOError (Registry.delValue (registryKey env) (r wipeFromRegistryWithPrompt :: RegistryBasedEnvironment -> String -> IO () wipeFromRegistryWithPrompt env name = do - putStrLn $ "Deleting variable '" ++ name ++ "' from '" ++ registryKeyPath env ++ "'..." - agreed <- Utils.promptToContinue - when agreed $ wipeFromRegistry env name + putStrLn $ "Deleting variable '" ++ name ++ "' from '" ++ registryKeyPath env ++ "'..." + agreed <- Utils.promptToContinue + when agreed $ wipeFromRegistry env name getEnv :: String -> IO String getEnv = liftM (fromMaybe "") . System.Environment.lookupEnv diff --git a/src/Registry.hs b/src/Registry.hs index d6c3f26..a38ef00 100644 --- a/src/Registry.hs +++ b/src/Registry.hs @@ -4,21 +4,24 @@ - See LICENSE.txt for details. -} -module Registry ( delValue - , getString - , hkcu - , hklm - , setString - , KeyHandle ) where +module Registry + ( KeyHandle + , delValue + , getString + , setString + , hkcu + , hklm + ) where + +import Control.Exception (bracket) +import Data.Maybe (fromMaybe) +import Foreign.ForeignPtr (withForeignPtr) +import Foreign.Marshal.Alloc (alloca, allocaBytes) +import Foreign.Ptr (castPtr, plusPtr) +import Foreign.Storable (peek, poke, sizeOf) +import Graphics.Win32.Window (sendMessage) +import System.IO.Error (mkIOError, doesNotExistErrorType) -import Control.Exception ( bracket ) -import Data.Maybe ( fromMaybe ) -import Foreign.ForeignPtr ( withForeignPtr ) -import Foreign.Marshal.Alloc ( alloca, allocaBytes ) -import Foreign.Ptr ( castPtr, plusPtr ) -import Foreign.Storable ( peek, poke, sizeOf ) -import Graphics.Win32.Window ( sendMessage ) -import System.IO.Error ( mkIOError, doesNotExistErrorType ) import System.Win32.Types import System.Win32.Registry @@ -26,69 +29,69 @@ newtype KeyHandle = KeyHandle HKEY getType :: HKEY -> String -> String -> IO (Maybe RegValueType) getType key subKeyPath valueName = - bracket (regOpenKey key subKeyPath) regCloseKey $ \hKey -> - withForeignPtr hKey $ \p_key -> - withTString valueName $ \p_valueName -> - alloca $ \p_type -> do - ret <- c_RegQueryValueEx p_key p_valueName nullPtr p_type nullPtr nullPtr - case ret of - 0x0 -> do - type_ <- peek p_type - return $ Just type_ - 0x2 -> return Nothing - _ -> failWith "RegQueryValueEx" ret + bracket (regOpenKey key subKeyPath) regCloseKey $ \hKey -> + withForeignPtr hKey $ \p_key -> + withTString valueName $ \p_valueName -> + alloca $ \p_type -> do + ret <- c_RegQueryValueEx p_key p_valueName nullPtr p_type nullPtr nullPtr + case ret of + 0x0 -> do + type_ <- peek p_type + return $ Just type_ + 0x2 -> return Nothing + _ -> failWith "RegQueryValueEx" ret getString :: KeyHandle -> String -> String -> IO String getString (KeyHandle hKey) subKeyPath valueName = - bracket (regOpenKey hKey subKeyPath) regCloseKey $ \hSubKey -> - withForeignPtr hSubKey $ \p_key -> - withTString valueName $ \p_valueName -> - alloca $ \dataSizePtr -> do - poke dataSizePtr 0 - ret <- c_RegQueryValueEx p_key p_valueName nullPtr nullPtr nullPtr dataSizePtr - case ret of - 0x0 -> do - dataSize <- peek dataSizePtr - let newDataSize = dataSize + fromIntegral (sizeOf (undefined :: TCHAR)) - poke dataSizePtr newDataSize - allocaBytes (fromIntegral newDataSize) $ \dataPtr -> do - poke (castPtr $ plusPtr dataPtr $ fromIntegral dataSize) '\0' - failUnlessSuccess "RegQueryValueEx" $ - c_RegQueryValueEx p_key p_valueName nullPtr nullPtr dataPtr dataSizePtr - peekTString $ castPtr dataPtr - 0x2 -> ioError $ mkIOError doesNotExistErrorType "RegQueryValueEx" Nothing $ Just (subKeyPath ++ "\\" ++ valueName) - _ -> failWith "RegQueryValueEx" ret + bracket (regOpenKey hKey subKeyPath) regCloseKey $ \hSubKey -> + withForeignPtr hSubKey $ \p_key -> + withTString valueName $ \p_valueName -> + alloca $ \dataSizePtr -> do + poke dataSizePtr 0 + ret <- c_RegQueryValueEx p_key p_valueName nullPtr nullPtr nullPtr dataSizePtr + case ret of + 0x0 -> do + dataSize <- peek dataSizePtr + let newDataSize = dataSize + fromIntegral (sizeOf (undefined :: TCHAR)) + poke dataSizePtr newDataSize + allocaBytes (fromIntegral newDataSize) $ \dataPtr -> do + poke (castPtr $ plusPtr dataPtr $ fromIntegral dataSize) '\0' + failUnlessSuccess "RegQueryValueEx" $ + c_RegQueryValueEx p_key p_valueName nullPtr nullPtr dataPtr dataSizePtr + peekTString $ castPtr dataPtr + 0x2 -> ioError $ mkIOError doesNotExistErrorType "RegQueryValueEx" Nothing $ Just (subKeyPath ++ "\\" ++ valueName) + _ -> failWith "RegQueryValueEx" ret setString :: KeyHandle -> String -> String -> String -> IO () setString (KeyHandle hKey) subKeyPath valueName valueValue = - bracket (regOpenKey hKey subKeyPath) regCloseKey $ \subKey -> - withTString valueValue $ \p_valueValue -> do - type_ <- getType hKey subKeyPath valueName - regSetValueEx subKey valueName (fromMaybe rEG_SZ type_) p_valueValue $ (length valueValue + 1) * sizeOf (undefined :: TCHAR) - notifyEnvironmentUpdate + bracket (regOpenKey hKey subKeyPath) regCloseKey $ \subKey -> + withTString valueValue $ \p_valueValue -> do + type_ <- getType hKey subKeyPath valueName + regSetValueEx subKey valueName (fromMaybe rEG_SZ type_) p_valueValue $ (length valueValue + 1) * sizeOf (undefined :: TCHAR) + notifyEnvironmentUpdate notifyEnvironmentUpdate :: IO () notifyEnvironmentUpdate = - withTString "Environment" $ \p_lparam -> do - let wparam = 0 - let lparam = fromIntegral $ castPtrToUINTPtr p_lparam - let hwnd = castUINTPtrToPtr 0xffff - _ <- sendMessage hwnd wM_SETTINGCHANGE wparam lparam - return () - where - wM_SETTINGCHANGE = 0x1A + withTString "Environment" $ \p_lparam -> do + let wparam = 0 + let lparam = fromIntegral $ castPtrToUINTPtr p_lparam + let hwnd = castUINTPtrToPtr 0xffff + _ <- sendMessage hwnd wM_SETTINGCHANGE wparam lparam + return () + where + wM_SETTINGCHANGE = 0x1A delValue :: KeyHandle -> String -> String -> IO () delValue (KeyHandle hKey) subKeyPath valueName = - bracket (regOpenKey hKey subKeyPath) regCloseKey $ \subKey -> - withForeignPtr subKey $ \subKeyPtr -> - withTString valueName $ \p_valueName -> do - ret <- c_RegDeleteValue subKeyPtr p_valueName - notifyEnvironmentUpdate - case ret of - 0x0 -> return () - 0x2 -> ioError $ mkIOError doesNotExistErrorType "RegQueryValueEx" Nothing $ Just (subKeyPath ++ "\\" ++ valueName) - _ -> failWith "RegDeleteValue" ret + bracket (regOpenKey hKey subKeyPath) regCloseKey $ \subKey -> + withForeignPtr subKey $ \subKeyPtr -> + withTString valueName $ \p_valueName -> do + ret <- c_RegDeleteValue subKeyPtr p_valueName + notifyEnvironmentUpdate + case ret of + 0x0 -> return () + 0x2 -> ioError $ mkIOError doesNotExistErrorType "RegQueryValueEx" Nothing $ Just (subKeyPath ++ "\\" ++ valueName) + _ -> failWith "RegDeleteValue" ret hkcu :: KeyHandle hkcu = KeyHandle hKEY_CURRENT_USER diff --git a/src/Utils.hs b/src/Utils.hs index 21ee67b..ec15405 100644 --- a/src/Utils.hs +++ b/src/Utils.hs @@ -6,24 +6,24 @@ module Utils where -import Control.Monad ( liftM ) -import Data.Char ( toLower ) -import System.IO ( hFlush, stdout ) +import Control.Monad (liftM) +import Data.Char (toLower) +import System.IO (hFlush, stdout) prompt :: String -> IO String prompt banner = do - putStr banner - hFlush stdout - getLine + putStr banner + hFlush stdout + getLine promptYesNo :: String -> IO Bool promptYesNo banner = do - response <- liftM (map toLower) $ prompt banner - if response `elem` yeses - then return True - else if response `elem` noes - then return False - else promptToContinue + response <- liftM (map toLower) $ prompt banner + if response `elem` yeses + then return True + else if response `elem` noes + then return False + else promptToContinue where yeses = ["y", "yes"] noes = ["n", "no"] |