[project @ 2001-08-16 11:06:10 by simonmar]
[ghc-hetmet.git] / ghc / compiler / main / DriverUtil.hs
index 75cda59..264be5c 100644 (file)
@@ -1,5 +1,5 @@
 -----------------------------------------------------------------------------
--- $Id: DriverUtil.hs,v 1.1 2000/10/11 11:54:58 simonmar Exp $
+-- $Id: DriverUtil.hs,v 1.27 2001/08/16 11:06:10 simonmar Exp $
 --
 -- Utils for the driver
 --
@@ -9,93 +9,76 @@
 
 module DriverUtil where
 
+#include "../includes/config.h"
 #include "HsVersions.h"
 
-import Config
 import Util
+import Panic
+import Config          ( cLeadingUnderscore )
 
 import IOExts
 import Exception
 import Dynamic
+import RegexString
 
+import Directory       ( getDirectoryContents )
 import IO
-import System
-import Directory
 import List
 import Char
 import Monad
 
+
 -----------------------------------------------------------------------------
 -- Errors
 
-short_usage = "Usage: For basic information, try the `--help' option."
-   
-long_usage = do
-  let usage_file = "ghc-usage.txt"
-      usage_path = findFile usage_file (cGHC_DRIVER_DIR ++ '/':usage_file)
-  usage <- readFile usage_path
-  dump usage
-  exitWith ExitSuccess
+-----------------------------------------------------------------------------
+-- 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
-     dump "" = return ()
-     dump ('$':'$':s) = hPutStr stderr get_prog_name >> dump s
-     dump (c:s) = hPutChar stderr c >> dump s
-
-version_str = cProjectVersion
-
-data BarfKind
-  = PhaseFailed String ExitCode
-  | Interrupted
-  | UsageError String                  -- prints the short usage msg after the error
-  | OtherError String                  -- just prints the error message
-  deriving Eq
-
-GLOBAL_VAR(prog_name, "ghc", String)
-
-get_prog_name = unsafePerformIO (readIORef prog_name) -- urk!
+       look h = do
+           l <- hGetLine h
+           case () of
+               () | null l -> look h
+                  | prefixMatch "#" l -> look h
+                  | prefixMatch "{-# LINE" l -> look h   -- -}
+                  | Just (opts:_) <- matchRegex optionRegex l
+                       -> do rest <- look h
+                              return (words opts ++ rest)
+                  | otherwise -> return []
+
+optionRegex = mkRegex "\\{-#[ \t]+OPTIONS[ \t]+(.*)#-\\}"   -- -}
 
-instance Show BarfKind where
-  showsPrec _ e = showString get_prog_name . showString ": " . showBarf e
-
-showBarf (UsageError str) = showString str . showChar '\n' . showString short_usage
-showBarf (OtherError str) = showString str
-showBarf (PhaseFailed phase code) = 
-       showString phase . showString " failed, code = " . shows code
-showBarf (Interrupted) = showString "interrupted"
-
-unknownFlagErr f = throwDyn (UsageError ("unrecognised flag: " ++ f))
+-----------------------------------------------------------------------------
+-- A version of getDirectoryContents that is non-fatal if the
+-- directory doesn't exist.
 
-barfKindTc = mkTyCon "BarfKind"
-instance Typeable BarfKind where
-  typeOf _ = mkAppTy barfKindTc []
+softGetDirectoryContents d
+   = IO.catch (getDirectoryContents d)
+         (\_ -> do hPutStrLn stderr 
+                         ("WARNING: error while reading directory " ++ d)
+                   return []
+         )
 
 -----------------------------------------------------------------------------
--- Finding files in the installation
-
-GLOBAL_VAR(topDir, clibdir, String)
-
-       -- grab the last -B option on the command line, and
-       -- set topDir to its value.
-setTopDir :: [String] -> IO [String]
-setTopDir args = do
-  let (minusbs, others) = partition (prefixMatch "-B") args
-  (case minusbs of
-    []   -> writeIORef topDir clibdir
-    some -> writeIORef topDir (drop 2 (last some)))
-  return others
-
-findFile name alt_path = unsafePerformIO (do
-  top_dir <- readIORef topDir
-  let installed_file = top_dir ++ '/':name
-  let inplace_file   = top_dir ++ '/':cCURRENT_DIR ++ '/':alt_path
-  b <- doesFileExist inplace_file
-  if b  then return inplace_file
-       else return installed_file
- )
+-- 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))
+
 my_partition :: (a -> Maybe b) -> [a] -> ([(a,b)],[a])
 my_partition _ [] = ([],[])
 my_partition p (a:as)
@@ -105,26 +88,26 @@ my_partition p (a:as)
        Just b  -> ((a,b):bs,cs)
 
 my_prefix_match :: String -> String -> Maybe String
-my_prefix_match [] rest = Just rest
-my_prefix_match (_:_) [] = Nothing
+my_prefix_match []    rest = Just rest
+my_prefix_match (_:_) []   = Nothing
 my_prefix_match (p:pat) (r:rest)
   | p == r    = my_prefix_match pat rest
   | otherwise = Nothing
 
-prefixMatch :: Eq a => [a] -> [a] -> Bool
-prefixMatch [] _str = True
-prefixMatch _pat [] = False
-prefixMatch (p:ps) (s:ss) | p == s    = prefixMatch ps ss
-                         | otherwise = False
-
-postfixMatch :: String -> String -> Bool
-postfixMatch pat str = prefixMatch (reverse pat) (reverse str)
-
 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] 
@@ -141,7 +124,28 @@ addNoDups var x = do
   xs <- readIORef var
   unless (x `elem` xs) $ writeIORef var (x:xs)
 
-remove_suffix :: Char -> String -> String
+------------------------------------------------------
+--             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")
+splitFilename3 :: String -> (String,String,Suffix)
+splitFilename3 str
+   = let (dir, rest) = split_longest_prefix str '/'
+        (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  = reverse suf
   | otherwise = reverse pre
@@ -155,7 +159,17 @@ take_longest_prefix :: String -> Char -> String
 take_longest_prefix s c = reverse pre
   where (_suf,pre) = break (==c) (reverse s)
 
-newsuf :: String -> String -> String
+-- split a string at the last occurence of 'c', returning the two
+-- parts of the string with the 'c' removed.  If the string contains
+-- no 'c's, the entire string is returned in the second component.
+split_longest_prefix :: String -> Char -> (String,String)
+split_longest_prefix s c
+  = case pre of
+       []      -> ([], reverse suf)
+       (_:pre) -> (reverse pre, reverse suf)
+  where (suf,pre) = break (==c) (reverse s)
+
+newsuf :: String -> Suffix -> String
 newsuf suf s = remove_suffix '.' s ++ suf
 
 -- getdir strips the filename off the input string, returning the directory.
@@ -169,9 +183,4 @@ newdir dir s = dir ++ '/':drop_longest_prefix s '/'
 remove_spaces :: String -> String
 remove_spaces = reverse . dropWhile isSpace . reverse . dropWhile isSpace
 
-booter_version
- = case "\ 
-       \ __GLASGOW_HASKELL__" of
-    ' ':n:ns -> n:'.':ns
-    ' ':m    -> m