@@ -28,17 +28,20 @@ import Paths_alex ( version, getDataDir )
28
28
import Control.Exception as Exception ( block , unblock , catch , throw )
29
29
#endif
30
30
#if __GLASGOW_HASKELL__ >= 610
31
- import Control.Exception ( bracketOnError )
31
+ import Control.Exception ( bracketOnError , handleJust )
32
32
#endif
33
- import Control.Monad ( when , liftM )
33
+ import System.IO.Error (isDoesNotExistError )
34
+ import Control.Monad ( guard , when , liftM )
34
35
import Data.Char ( chr )
35
36
import Data.List ( isSuffixOf , nub )
36
37
import Data.Version ( showVersion )
37
38
import System.Console.GetOpt ( getOpt , usageInfo , ArgOrder (.. ), OptDescr (.. ), ArgDescr (.. ) )
38
- import System.Directory ( removeFile )
39
+ import System.Directory ( renameFile , removeFile )
39
40
import System.Environment ( getProgName , getArgs )
41
+ import System.FilePath (splitFileName )
40
42
import System.Exit ( ExitCode (.. ), exitWith )
41
43
import System.IO ( stderr , Handle , IOMode (.. ), openFile , hClose , hPutStr , hPutStrLn )
44
+ import qualified System.IO as IO ( openTempFileWithDefaultPermissions )
42
45
#if __GLASGOW_HASKELL__ >= 612
43
46
import System.IO ( hGetContents , hSetEncoding , utf8 )
44
47
#endif
@@ -66,6 +69,37 @@ alexOpenFile file mode = do
66
69
alexOpenFile = openFile
67
70
#endif
68
71
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
+
69
103
-- `main' decodes the command line arguments and calls `alex'.
70
104
71
105
main :: IO ()
@@ -169,11 +203,7 @@ alex cli file basename script = do
169
203
170
204
scheme <- getScheme directives
171
205
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
177
207
178
208
let scanner2, scanner_final :: Scanner
179
209
scs :: [StartCode ]
@@ -242,7 +272,6 @@ alex cli file basename script = do
242
272
tmplt <- alexReadFile $ template_dir ++ " /AlexTemplate.hs"
243
273
hPutStr out_h tmplt
244
274
245
- hClose out_h
246
275
finish_info
247
276
248
277
getScheme :: [Directive ] -> IO Scheme
0 commit comments