@@ -28,17 +28,20 @@ import Paths_alex ( version, getDataDir )
2828import Control.Exception as Exception ( block , unblock , catch , throw )
2929#endif
3030#if __GLASGOW_HASKELL__ >= 610
31- import Control.Exception ( bracketOnError )
31+ import Control.Exception ( bracketOnError , handleJust )
3232#endif
33- import Control.Monad ( when , liftM )
33+ import System.IO.Error (isDoesNotExistError )
34+ import Control.Monad ( guard , when , liftM )
3435import Data.Char ( chr )
3536import Data.List ( isSuffixOf , nub )
3637import Data.Version ( showVersion )
3738import System.Console.GetOpt ( getOpt , usageInfo , ArgOrder (.. ), OptDescr (.. ), ArgDescr (.. ) )
38- import System.Directory ( removeFile )
39+ import System.Directory ( renameFile , removeFile )
3940import System.Environment ( getProgName , getArgs )
41+ import System.FilePath (splitFileName )
4042import System.Exit ( ExitCode (.. ), exitWith )
4143import System.IO ( stderr , Handle , IOMode (.. ), openFile , hClose , hPutStr , hPutStrLn )
44+ import qualified System.IO as IO ( openTempFileWithDefaultPermissions )
4245#if __GLASGOW_HASKELL__ >= 612
4346import System.IO ( hGetContents , hSetEncoding , utf8 )
4447#endif
@@ -66,6 +69,37 @@ alexOpenFile file mode = do
6669alexOpenFile = openFile
6770#endif
6871
72+ openTempFileWithDefaultPermissions :: FilePath -> String -> IO (FilePath , Handle )
73+ #if __GLASGOW_HASKELL__ >= 612
74+ openTempFileWithDefaultPermissions dir template = do
75+ (file, h) <- IO. openTempFileWithDefaultPermissions dir template
76+ hSetEncoding h utf8
77+ return (file, h)
78+ #else
79+ openTempFileWithDefaultPermissions = IO. openTempFileWithDefaultPermissions
80+ #endif
81+
82+ tryRemoveFile :: FilePath -> IO ()
83+ tryRemoveFile name = handleJust (guard . isDoesNotExistError) return (removeFile name)
84+
85+ createAtomically :: FilePath -> (Handle -> IO a ) -> IO a
86+ createAtomically o_file action = bracketOnError open cleanup $ \ (o_file_tmp, h) -> do
87+ r <- action h
88+ hClose h
89+ renameFile o_file_tmp o_file
90+ return r
91+ where
92+ open :: IO (FilePath , Handle )
93+ open = openTempFileWithDefaultPermissions dir template
94+ where
95+ (dir, file) = splitFileName o_file
96+ template = file <> " ~"
97+
98+ cleanup :: (FilePath , Handle ) -> IO ()
99+ cleanup (o_file_tmp, h) = do
100+ hClose h
101+ tryRemoveFile o_file_tmp
102+
69103-- `main' decodes the command line arguments and calls `alex'.
70104
71105main :: IO ()
@@ -169,11 +203,7 @@ alex cli file basename script = do
169203
170204 scheme <- getScheme directives
171205
172- -- open the output file; remove it if we encounter an error
173- bracketOnError
174- (alexOpenFile o_file WriteMode )
175- (\ h -> do hClose h; removeFile o_file)
176- $ \ out_h -> do
206+ createAtomically o_file $ \ out_h -> do
177207
178208 let scanner2, scanner_final :: Scanner
179209 scs :: [StartCode ]
@@ -242,7 +272,6 @@ alex cli file basename script = do
242272 tmplt <- alexReadFile $ template_dir ++ " /AlexTemplate.hs"
243273 hPutStr out_h tmplt
244274
245- hClose out_h
246275 finish_info
247276
248277getScheme :: [Directive ] -> IO Scheme
0 commit comments