1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
|
-----------------------------------------------------------------------------
-- $Id: DriverUtil.hs,v 1.43 2004/08/13 13:07:02 simonmar Exp $
--
-- Utils for the driver
--
-- (c) The University of Glasgow 2000
--
-----------------------------------------------------------------------------
module DriverUtil (
getOptionsFromSource, softGetDirectoryContents,
createDirectoryHierarchy, doesDirNameExist, prefixUnderscore,
unknownFlagErr, unknownFlagsErr, missingArgErr,
later, handleDyn, handle,
split, add, addNoDups,
Suffix, splitFilename, getFileSuffix,
splitFilename3, remove_suffix, split_longest_prefix,
replaceFilenameSuffix, directoryOf, replaceFilenameDirectory,
remove_spaces, escapeSpaces,
) where
#include "../includes/ghcconfig.h"
#include "HsVersions.h"
import Util
import Panic
import Config ( cLeadingUnderscore )
import EXCEPTION ( Exception(..), finally, throwDyn, catchDyn, throw )
import qualified EXCEPTION as Exception
import DYNAMIC
import DATA_IOREF ( IORef, readIORef, writeIORef )
import Directory
import IO
import List
import Char
import Monad
-----------------------------------------------------------------------------
-- Reading OPTIONS pragmas
getOptionsFromSource
:: String -- input file
-> IO [String] -- options, if any
getOptionsFromSource file
= do h <- openFile file ReadMode
catchJust ioErrors (look h `finally` hClose h)
(\e -> if isEOFError e then return [] else ioError e)
where
look h = do
l' <- hGetLine h
let l = remove_spaces l'
case () of
() | null l -> look h
| prefixMatch "#" l -> look h
| prefixMatch "{-# LINE" l -> look h -- -}
| Just opts <- matchOptions l
-> do rest <- look h
return (words opts ++ rest)
| otherwise -> return []
matchOptions s
| Just s1 <- maybePrefixMatch "{-#" s, -- -}
Just s2 <- maybePrefixMatch "OPTIONS" (remove_spaces s1),
Just s3 <- maybePrefixMatch "}-#" (reverse s2)
= Just (reverse s3)
| otherwise
= Nothing
-----------------------------------------------------------------------------
-- A version of getDirectoryContents that is non-fatal if the
-- directory doesn't exist.
softGetDirectoryContents d
= IO.catch (getDirectoryContents d)
(\_ -> do hPutStrLn stderr
("WARNING: error while reading directory " ++ d)
return []
)
-----------------------------------------------------------------------------
-- Create a hierarchy of directories
createDirectoryHierarchy :: FilePath -> IO ()
createDirectoryHierarchy dir = do
b <- doesDirectoryExist dir
when (not b) $ do
createDirectoryHierarchy (directoryOf dir)
createDirectory dir
-----------------------------------------------------------------------------
-- Verify that the 'dirname' portion of a FilePath exists.
--
doesDirNameExist :: FilePath -> IO Bool
doesDirNameExist fpath = doesDirectoryExist (directoryOf fpath)
-----------------------------------------------------------------------------
-- Prefixing underscore to linker-level names
prefixUnderscore :: String -> String
prefixUnderscore
| cLeadingUnderscore == "YES" = ('_':)
| otherwise = id
-----------------------------------------------------------------------------
-- Utils
unknownFlagErr :: String -> a
unknownFlagErr f = throwDyn (UsageError ("unrecognised flag: " ++ f))
unknownFlagsErr :: [String] -> a
unknownFlagsErr fs = throwDyn (UsageError ("unrecognised flags: " ++ unwords fs))
missingArgErr :: String -> a
missingArgErr f = throwDyn (UsageError ("missing argument for flag: " ++ f))
later = flip finally
handleDyn :: Typeable ex => (ex -> IO a) -> IO a -> IO a
handleDyn = flip catchDyn
handle :: (Exception -> IO a) -> IO a -> IO a
#if __GLASGOW_HASKELL__ < 501
handle = flip Exception.catchAllIO
#else
handle h f = f `Exception.catch` \e -> case e of
ExitException _ -> throw e
_ -> h e
#endif
split :: Char -> String -> [String]
split c s = case rest of
[] -> [chunk]
_:rest -> chunk : split c rest
where (chunk, rest) = break (==c) s
add :: IORef [a] -> a -> IO ()
add var x = do
xs <- readIORef var
writeIORef var (x:xs)
addNoDups :: Eq a => IORef [a] -> a -> IO ()
addNoDups var x = do
xs <- readIORef var
unless (x `elem` xs) $ writeIORef var (x:xs)
------------------------------------------------------
-- Filename manipulation
------------------------------------------------------
type Suffix = String
splitFilename :: String -> (String,Suffix)
splitFilename f = split_longest_prefix f (=='.')
getFileSuffix :: String -> Suffix
getFileSuffix f = drop_longest_prefix f (=='.')
-- "foo/bar/xyzzy.ext" -> ("foo/bar", "xyzzy.ext")
splitFilenameDir :: String -> (String,String)
splitFilenameDir str
= let (dir, rest) = split_longest_prefix str isPathSeparator
real_dir | null dir = "."
| otherwise = dir
in (real_dir, rest)
-- "foo/bar/xyzzy.ext" -> ("foo/bar", "xyzzy", ".ext")
splitFilename3 :: String -> (String,String,Suffix)
splitFilename3 str
= let (dir, rest) = split_longest_prefix str isPathSeparator
(name, ext) = splitFilename rest
real_dir | null dir = "."
| otherwise = dir
in (real_dir, name, ext)
remove_suffix :: Char -> String -> Suffix
remove_suffix c s
| null pre = s
| otherwise = reverse pre
where (suf,pre) = break (==c) (reverse s)
drop_longest_prefix :: String -> (Char -> Bool) -> String
drop_longest_prefix s pred = reverse suf
where (suf,_pre) = break pred (reverse s)
take_longest_prefix :: String -> (Char -> Bool) -> String
take_longest_prefix s pred = reverse pre
where (_suf,pre) = break pred (reverse s)
-- split a string at the last character where 'pred' is True,
-- returning a pair of strings. The first component holds the string
-- up (but not including) the last character for which 'pred' returned
-- True, the second whatever comes after (but also not including the
-- last character).
--
-- If 'pred' returns False for all characters in the string, the original
-- string is returned in the second component (and the first one is just
-- empty).
split_longest_prefix :: String -> (Char -> Bool) -> (String,String)
split_longest_prefix s pred
= case pre of
[] -> ([], reverse suf)
(_:pre) -> (reverse pre, reverse suf)
where (suf,pre) = break pred (reverse s)
replaceFilenameSuffix :: FilePath -> Suffix -> FilePath
replaceFilenameSuffix s suf = remove_suffix '.' s ++ suf
-- directoryOf strips the filename off the input string, returning
-- the directory.
directoryOf :: FilePath -> String
directoryOf = fst . splitFilenameDir
replaceFilenameDirectory :: FilePath -> String -> FilePath
replaceFilenameDirectory s dir
= dir ++ '/':drop_longest_prefix s isPathSeparator
remove_spaces :: String -> String
remove_spaces = reverse . dropWhile isSpace . reverse . dropWhile isSpace
escapeSpaces :: String -> String
escapeSpaces = foldr (\c s -> if isSpace c then '\\':c:s else c:s) ""
isPathSeparator :: Char -> Bool
isPathSeparator ch =
#ifdef mingw32_TARGET_OS
ch == '/' || ch == '\\'
#else
ch == '/'
#endif
|