From f48ba11a99ebce67b72a122d264515a5b19dc1df Mon Sep 17 00:00:00 2001
From: simonmar <unknown>
Date: Tue, 7 Nov 2000 15:28:36 +0000
Subject: [PATCH] [project @ 2000-11-07 15:28:36 by simonmar] add hsc2hs,
 missed in the merge

---
 ghc/utils/hsc2hs/Main.hs        | 303 ++++++++++++++++++++++++++++++++
 ghc/utils/hsc2hs/Makefile       |  58 ++++++
 ghc/utils/hsc2hs/hsc2hs.sh      |   1 +
 ghc/utils/hsc2hs/template-hsc.h |  71 ++++++++
 4 files changed, 433 insertions(+)
 create mode 100644 ghc/utils/hsc2hs/Main.hs
 create mode 100644 ghc/utils/hsc2hs/Makefile
 create mode 100644 ghc/utils/hsc2hs/hsc2hs.sh
 create mode 100644 ghc/utils/hsc2hs/template-hsc.h

diff --git a/ghc/utils/hsc2hs/Main.hs b/ghc/utils/hsc2hs/Main.hs
new file mode 100644
index 000000000000..edd780d7d3a2
--- /dev/null
+++ b/ghc/utils/hsc2hs/Main.hs
@@ -0,0 +1,303 @@
+-----------------------------------------------------------------------------
+-- $Id: Main.hs,v 1.2 2000/11/07 15:28:36 simonmar Exp $
+--
+-- (originally "GlueHsc.hs" by Marcin 'Qrczak' Kowalczyk)
+--
+-- Program for converting .hsc files to .hs files, by converting the
+-- file into a C program which is run to generate the Haskell source.
+-- Certain items known only to the C compiler can then be used in
+-- the Haskell module; for example #defined constants, byte offsets
+-- within structures, etc.
+--
+-- See the documentation in the Users' Guide for more details.
+
+import GetOpt
+import System    (getProgName, getArgs, ExitCode(..), system, exitWith, exitFailure)
+import Directory (removeFile)
+import Parsec
+import Monad     (liftM, liftM2, when)
+import Char      (ord, intToDigit, isSpace, isAlphaNum, toUpper)
+
+data Flag
+    = Help
+    | Template String
+    | Compiler String
+    | Linker String
+    | CompFlag String
+    | LinkFlag String
+
+options :: [OptDescr Flag]
+options = [
+    Option "t" ["template"] (ReqArg Template "FILE") "template file",
+    Option ""  ["cc"]       (ReqArg Compiler "PROG") "C compiler to use",
+    Option ""  ["ld"]       (ReqArg Linker   "PROG") "linker to use",
+    Option ""  ["cflag"]    (ReqArg CompFlag "FLAG") "flag to pass to the C compiler",
+    Option ""  ["lflag"]    (ReqArg LinkFlag "FLAG") "flag to pass to the linker",
+    Option ""  ["help"]     (NoArg  Help)            "display this help and exit"]
+
+main :: IO ()
+main = do
+    prog <- getProgName
+    let header = "Usage: "++prog++" [OPTIONS...] INPUT.hsc [...]"
+    args <- getArgs
+    case getOpt Permute options args of
+        (flags, _, _) | any isHelp flags -> putStrLn (usageInfo header options)
+            where isHelp Help = True; isHelp _ = False
+        (_,     [],    [])   -> putStrLn (prog++": No input files")
+        (flags, files, [])   -> mapM_ (processFile flags) files
+        (_,     _,     errs) -> do
+            mapM_ putStrLn errs
+            putStrLn (usageInfo header options)
+            exitFailure
+
+processFile :: [Flag] -> String -> IO ()
+processFile flags name = do
+    parsed <- parseFromFile parser name
+    case parsed of
+        Left err -> print err
+        Right toks -> output flags name toks
+
+data Token
+    = Text String
+    | Special String String
+
+parser :: Parser [Token]
+parser = many (text <|> special)
+
+text :: Parser Token
+text = liftM Text $ many1 $ satisfy (/= '#') <|> try (string "##" >> return '#')
+
+special :: Parser Token
+special = do
+    char '#'
+    skipMany (oneOf " \t")
+    key <- liftM2 (:) (letter <|> char '_') (many (alphaNum <|> char '_'))
+        <?> "hsc directive"
+    skipMany (oneOf " \t")
+    arg <- argument pzero
+    return (Special key arg)
+
+argument :: Parser String -> Parser String
+argument eol = liftM concat $ many
+    (   many1 (noneOf "\n\"\'()/[\\]{}")
+    <|> eol
+    <|> (do char '\"'; a <- cString '\''; char '\"'; return ("\""++a++"\""))
+    <|> (do char '\''; a <- cString '\"'; char '\''; return ("\'"++a++"\'"))
+    <|> (do char '('; a <- nested; char ')'; return ("("++a++")"))
+    <|> (do try (string "/*"); comment; return " ")
+    <|> (do try (string "//"); skipMany (satisfy (/= '\n')); return " ")
+    <|> string "/"
+    <|> (do char '['; a <- nested; char ']'; return ("["++a++"]"))
+    <|> (do char '\\'; a <- anyChar; return ['\\',a])
+    <|> (do char '{'; a <- nested; char '}'; return ("{"++a++"}"))
+    <?> "C expression")
+    where nested = argument (string "\n")
+
+comment :: Parser ()
+comment = (do skipMany1 (noneOf "*"); comment)
+      <|> (do try (string "*/"); return ())
+      <|> (do char '*'; comment)
+      <?> "C comment"
+
+cString :: Char -> Parser String
+cString otherQuote = liftM concat $ many
+    (   many1 (noneOf "\n\\\'\"")
+    <|> string [otherQuote]
+    <|> (do char '\\'; a <- anyChar; return ['\\',a])
+    <?> "C character or string")
+
+output :: [Flag] -> String -> [Token] -> IO ()
+output flags name toks = let
+    baseName = case reverse name of
+        'c':base -> reverse base
+        _        -> name++".hs"
+    cProgName = baseName++"c_make_hs.c"
+    oProgName = baseName++"c_make_hs.o"
+    progName  = baseName++"c_make_hs"
+    outHsName = baseName
+    outHName  = baseName++".h"
+    outCName  = baseName++".c"
+    
+    execProgName = case progName of
+        '/':_ -> progName
+        _     -> "./"++progName
+    
+    specials = [(key, arg) | Special key arg <- toks]
+    
+    needsC = any (\(key, _) -> key=="def") specials
+    needsH = needsC
+    
+    includeGuard = map fixChar outHName
+        where
+        fixChar c | isAlphaNum c = toUpper c
+                  | otherwise    = '_'
+    
+    in do
+    
+    compiler <- case [c | Compiler c <- flags] of
+        []  -> return "ghc"
+        [c] -> return c
+        _   -> onlyOne "compiler"
+    linker <- case [l | Linker l <- flags] of
+        []  -> return "gcc"
+        [l] -> return l
+        _   -> onlyOne "linker"
+        
+    writeFile cProgName $
+        concat ["#include \""++t++"\"\n" | Template t <- flags] ++
+        outHeaderCProg specials ++
+        "\nint main (void)\n{\n" ++
+        outHeaderHs (if needsH then Just outHName else Nothing) specials ++
+        concatMap outTokenHs toks ++
+        "    return 0;\n}\n"
+    
+    compilerStatus <- system $
+        compiler++
+        " -c"++
+        concat [" "++f | CompFlag f <- flags]++
+        " "++cProgName++
+        " -o "++oProgName
+    case compilerStatus of
+        e@(ExitFailure _) -> exitWith e
+        _                 -> return ()
+    removeFile cProgName
+    
+    linkerStatus <- system $
+        linker++
+        concat [" "++f | LinkFlag f <- flags]++
+        " "++oProgName++
+        " -o "++progName
+    case linkerStatus of
+        e@(ExitFailure _) -> exitWith e
+        _                 -> return ()
+    removeFile oProgName
+    
+    system (execProgName++" >"++outHsName)
+    removeFile progName
+    
+    when needsH $ writeFile outHName $
+        "#ifndef "++includeGuard++"\n\
+        \#define "++includeGuard++"\n\
+        \#include <HsFFI.h>\n"++
+        concatMap outTokenH specials++
+        "#endif\n"
+    
+    when needsC $ writeFile outCName $
+        "#include \""++outHName++"\"\n"++
+        concatMap outTokenC specials
+
+onlyOne :: String -> IO a
+onlyOne what = do
+    putStrLn ("Only one "++what++" may be specified")
+    exitFailure
+
+outHeaderCProg :: [(String, String)] -> String
+outHeaderCProg = concatMap $ \(key, arg) -> case key of
+    "include"           -> "#include "++arg++"\n"
+    "define"            -> "#define "++arg++"\n"
+    "def"               -> case arg of
+        's':'t':'r':'u':'c':'t':' ':_ -> arg++"\n"
+        't':'y':'p':'e':'d':'e':'f':' ':_ -> arg++"\n"
+        _ -> ""
+    _ | conditional key -> "#"++key++" "++arg++"\n"
+    _                   -> ""
+
+outHeaderHs :: Maybe String -> [(String, String)] -> String
+outHeaderHs inH toks =
+    concatMap outSpecial toks ++
+    includeH ++
+    "    hsc_end_options();\n\n"
+    where
+    outSpecial (key, arg) = case key of
+        "include" -> case inH of
+            Nothing -> out ("-#include "++arg)
+            Just _  -> ""
+        "define" -> case inH of
+            Nothing -> out ("-optc-D"++toOptD arg)
+            Just _  -> ""
+        "option" -> out arg
+        _ | conditional key -> "#"++key++" "++arg++"\n"
+        _ -> ""
+    toOptD arg = case break isSpace arg of
+        (name, "")      -> name
+        (name, _:value) -> name++'=':dropWhile isSpace value
+    includeH = case inH of
+        Nothing   -> ""
+        Just name -> out ("-#include \""++name++"\"")
+    out s = "    hsc_option (\""++showCString s++"\");\n"
+
+outTokenHs :: Token -> String
+outTokenHs (Text s) = "    fputs (\""++showCString s++"\", stdout);\n"
+outTokenHs (Special key arg) = case key of
+    "include"           -> ""
+    "define"            -> ""
+    "option"            -> ""
+    "def"               -> ""
+    _ | conditional key -> "#"++key++" "++arg++"\n"
+    _                   -> "    hsc_"++key++" ("++arg++");\n"
+
+outTokenH :: (String, String) -> String
+outTokenH (key, arg) = case key of
+    "include" -> "#include "++arg++"\n"
+    "define" -> "#define " ++arg++"\n"
+    "def" -> case arg of
+        's':'t':'r':'u':'c':'t':' ':_ -> arg++"\n"
+        't':'y':'p':'e':'d':'e':'f':' ':_ -> arg++"\n"
+        'i':'n':'l':'i':'n':'e':' ':_ ->
+            "#ifdef __GNUC__\n\
+            \extern\n\
+            \#endif\n"++
+            arg++"\n"
+        _ -> "extern "++header++";\n"
+        where header = takeWhile (\c -> c/='{' && c/='=') arg
+    _ | conditional key -> "#"++key++" "++arg++"\n"
+    _ -> ""
+
+outTokenC :: (String, String) -> String
+outTokenC (key, arg) = case key of
+    "def" -> case arg of
+        's':'t':'r':'u':'c':'t':' ':_ -> ""
+        't':'y':'p':'e':'d':'e':'f':' ':_ -> ""
+        'i':'n':'l':'i':'n':'e':' ':_ ->
+            "#ifndef __GNUC__\n\
+            \extern\n\
+            \#endif\n"++
+            header++
+            "\n#ifndef __GNUC__\n\
+            \;\n\
+            \#else\n"++
+            body++
+            "\n#endif\n"
+        _ -> arg++"\n"
+        where (header, body) = span (\c -> c/='{' && c/='=') arg
+    _ | conditional key -> "#"++key++" "++arg++"\n"
+    _ -> ""
+
+conditional :: String -> Bool
+conditional "if"     = True
+conditional "ifdef"  = True
+conditional "ifndef" = True
+conditional "elif"   = True
+conditional "else"   = True
+conditional "endif"  = True
+conditional _        = False
+
+showCString :: String -> String
+showCString = concatMap showCChar
+    where
+    showCChar '\"' = "\\\""
+    showCChar '\'' = "\\\'"
+    showCChar '?'  = "\\?"
+    showCChar '\\' = "\\\\"
+    showCChar c | c >= ' ' && c <= '~' = [c]
+    showCChar '\a' = "\\a"
+    showCChar '\b' = "\\b"
+    showCChar '\f' = "\\f"
+    showCChar '\n' = "\\n\"\n           \""
+    showCChar '\r' = "\\r"
+    showCChar '\t' = "\\t"
+    showCChar '\v' = "\\v"
+    showCChar c    = ['\\',
+                      intToDigit (ord c `quot` 64),
+                      intToDigit (ord c `quot` 8 `mod` 8),
+                      intToDigit (ord c          `mod` 8)]
diff --git a/ghc/utils/hsc2hs/Makefile b/ghc/utils/hsc2hs/Makefile
new file mode 100644
index 000000000000..9a06547f4354
--- /dev/null
+++ b/ghc/utils/hsc2hs/Makefile
@@ -0,0 +1,58 @@
+# -----------------------------------------------------------------------------
+# $Id: Makefile,v 1.2 2000/11/07 15:28:36 simonmar Exp $
+
+TOP=../..
+include $(TOP)/mk/boilerplate.mk
+
+CURRENT_DIR=ghc/utils/hsc2hs
+
+INSTALLING=1
+
+HS_PROG           = hsc2hs-bin
+SRC_HC_OPTS      += -syslib util -syslib text
+
+INSTALLED_SCRIPT_PROG  = hsc2hs
+INPLACE_SCRIPT_PROG    = hsc2hs-inplace
+
+ifeq "$(INSTALLING)" "1"
+TOP_PWD 	:= $(prefix)
+SCRIPT_PROG 	=  $(INSTALLED_SCRIPT_PROG)
+else
+TOP_PWD 	:= $(FPTOOLS_TOP_ABS)
+SCRIPT_PROG 	=  $(INPLACE_SCRIPT_PROG)
+endif
+
+ifeq "$(INSTALLING)" "1"
+ifeq "$(BIN_DIST)"   "1"
+HSC2HS_DIR=$$\"\"libdir
+HSC2HS_EXTRA=
+else
+HSC2HS_DIR=$(libdir)
+HSC2HS_EXTRA=
+endif # BIN_DIST
+else
+HSC2HS_DIR=$(FPTOOLS_TOP_ABS)/$(CURRENT_DIR)
+HSC2HS_EXTRA=--cc=$(FPTOOLS_TOP_ABS)/$(CURRENT_DIR)/$(GHC_INPLACE)
+endif
+
+$(SCRIPT_PROG) : Makefile
+
+SCRIPT_SUBST_VARS = HSC2HS_DIR HS_PROG HSC2HS_EXTRA
+
+SCRIPT_OBJS=hsc2hs.sh
+INTERP=$(SHELL)
+
+INSTALL_SCRIPTS  += $(SCRIPT_PROG)
+INSTALL_LIBEXECS += $(HS_PROG)
+
+override datadir=$(libdir)
+INSTALL_DATAS += template-hsc.h
+
+# don't recurse on 'make install'
+#
+ifeq "$(INSTALLING)" "1"
+all clean veryclean maintainer-clean ::
+	$(MAKE) INSTALLING=0 BIN_DIST=0 $(MFLAGS) $@
+endif
+
+include $(TOP)/mk/target.mk
diff --git a/ghc/utils/hsc2hs/hsc2hs.sh b/ghc/utils/hsc2hs/hsc2hs.sh
new file mode 100644
index 000000000000..ba1e64a00af1
--- /dev/null
+++ b/ghc/utils/hsc2hs/hsc2hs.sh
@@ -0,0 +1 @@
+$HSC2HS_DIR/$HS_PROG -t $HSC2HS_DIR/template-hsc.h $HSC2HS_EXTRA "$@" 
diff --git a/ghc/utils/hsc2hs/template-hsc.h b/ghc/utils/hsc2hs/template-hsc.h
new file mode 100644
index 000000000000..265dd4d7d504
--- /dev/null
+++ b/ghc/utils/hsc2hs/template-hsc.h
@@ -0,0 +1,71 @@
+#include <HsFFI.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef offsetof
+#define offsetof(t, f) ((size_t) &((t *)0)->f)
+#endif
+
+static int hsc_options_started = 0;
+
+static void hsc_option (const char *s)
+{
+    if (!hsc_options_started)
+    {
+        printf ("{-# OPTIONS");
+        hsc_options_started = 1;
+    }
+    printf (" %s", s);
+}
+
+static void hsc_end_options (void)
+{
+    if (hsc_options_started) printf (" #-}\n");
+}
+
+#define hsc_const(x)                        \
+    if ((x) < 0)                            \
+        printf ("%ld", (long)(x));          \
+    else                                    \
+        printf ("%lu", (unsigned long)(x));
+
+#define hsc_const_str(x)                                          \
+    {                                                             \
+        const char *s = (x);                                      \
+        printf ("\"");                                            \
+        while (*s != '\0')                                        \
+        {                                                         \
+            if (*s == '"' || *s == '\\')                          \
+                printf ("\\%c", *s);                              \
+            else if (*s >= 0x20 && *s <= 0x7E)                    \
+                printf ("%c", *s);                                \
+            else                                                  \
+                printf ("\\%d%s",                                 \
+                        (unsigned char) *s,                       \
+                        s[1] >= '0' && s[1] <= '9' ? "\\&" : ""); \
+            s++;                                                  \
+        }                                                         \
+        printf ("\"");                                            \
+    }
+
+#define hsc_type(t)                                         \
+    if ((t)(int)(t)1.4 == (t)1.4)                           \
+        printf ("%s%d",                                     \
+                (t)(-1) < (t)0 ? "Int" : "Word",            \
+                sizeof (t) * 8);                            \
+    else                                                    \
+        printf ("%s",                                       \
+                sizeof (t) >  sizeof (double) ? "LDouble" : \
+                sizeof (t) == sizeof (double) ? "Double"  : \
+                "Float");
+
+#define hsc_peek(t, f) \
+    printf ("(\\hsc_ptr -> peekByteOff hsc_ptr %ld)", (long) offsetof (t, f));
+
+#define hsc_poke(t, f) \
+    printf ("(\\hsc_ptr -> pokeByteOff hsc_ptr %ld)", (long) offsetof (t, f));
+
+#define hsc_ptr(t, f) \
+    printf ("(\\hsc_ptr -> hsc_ptr `plusPtr` %ld)", (long) offsetof (t, f));
+
-- 
GitLab