diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2012, John Wiegley.  All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+- Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+- Neither the name of New Artisans LLC nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Main.hs b/Main.hs
new file mode 100644
--- /dev/null
+++ b/Main.hs
@@ -0,0 +1,444 @@
+module Main where
+
+import           Control.Applicative
+import           Control.Monad hiding (sequence)
+import           Control.Monad.Trans.State
+import           Data.Char
+import           Data.Foldable
+import           Data.List hiding (concat)
+import qualified Data.Map as M
+import           Data.Maybe
+import           Data.Traversable
+import           Language.C.Data.Ident
+import           Language.C.Data.InputStream
+import           Language.C.Data.Node
+import           Language.C.Data.Position
+import           Language.C.Parser
+import           Language.C.Pretty
+import           Language.C.Syntax.AST
+import           Language.C.System.GCC
+import           Language.C.System.Preprocess
+import           Prelude hiding (concat, sequence)
+import           System.Directory
+import           System.Environment
+import           System.FilePath
+import           System.IO
+import           Text.PrettyPrint as P
+import           Text.StringTemplate
+
+------------------------------ IMPURE FUNCTIONS ------------------------------
+
+-- Parsing of C headers begins with finding gcc so we can run the
+-- preprocessor.
+
+main :: IO ()
+main = do
+  gccExe <- findExecutable "gcc"
+  case gccExe of
+    Nothing      -> error "Cannot find 'gcc' executable on the PATH"
+    Just gccPath -> getArgs >>= parseFile gccPath
+
+-- Once gcc is found, setup to parse the C file by running the preprocessor.
+-- Then, identify the input file absolutely so we know which declarations to
+-- print out at the end.
+
+parseFile :: FilePath -> [String] -> IO ()
+parseFile gccPath args = do
+  fileName <- canonicalizePath $ last args
+  result   <- runPreprocessor (newGCC gccPath)
+                              (rawCppArgs (tail . init $ args) fileName)
+  case result of
+    Left err     -> error $ "Failed to run cpp: " ++ show err
+    Right stream -> do
+      let HscOutput hscs helpercs _ =
+            execState (parseCFile stream fileName (initPos fileName))
+                      newHscState
+      writeProducts (head args) fileName hscs helpercs
+
+-- Write out the gathered data
+
+writeProducts :: String -> FilePath -> [String] -> [String] -> IO ()
+writeProducts libName fileName hscs helpercs = do
+  let tmpl = unlines [ "#include <bindings.dsl.h>"
+                     , "#include <git2.h>"
+                     , "module $libName$.$cFileName$ where"
+                     , "#strict_import"
+                     , "" ]
+      vars = [ ("libName",   libName)
+             , ("cFileName", cap) ]
+      code = newSTMP tmpl
+      base = dropExtension . takeFileName $ fileName
+      cap  = capitalize base
+
+  let target = cap ++ ".hsc"
+  handle <- openFile target WriteMode
+
+  hPutStrLn handle $ toString $ setManyAttrib vars code
+
+  -- Sniff through the file again, but looking only for local #include's
+  contents <- readFile fileName
+  let includes = filter ("#include \"" `isPrefixOf`) (lines contents)
+
+  for_ includes $ \inc ->
+    hPutStrLn handle $ "import "
+                    ++ libName ++ "."
+                    ++ (capitalize . takeWhile (/= '.') . drop 10 $ inc)
+
+  traverse_ (hPutStrLn handle) hscs
+
+  hClose handle
+  putStrLn $ "Wrote " ++ target
+
+  when (length helpercs > 0) $ do
+    let targetc = cap ++ ".hsc.helper.c"
+    handlec <- openFile targetc WriteMode
+
+    hPutStrLn handlec "#include <bindings.cmacros.h>"
+    traverse_ (hPutStrLn handlec) includes
+    hPutStrLn handlec ""
+    traverse_ (hPutStrLn handlec) helpercs
+
+    hClose handlec
+    putStrLn $ "Wrote " ++ targetc
+
+  where capitalize [] = []
+        capitalize (x:xs) = toTitle x : xs
+
+------------------------------- PURE FUNCTIONS -------------------------------
+
+-- Rather than writing to the .hsc and .hsc.helper.c files directly from the
+-- IO monad, they are collected in an HscOutput value in the State monad.  The
+-- actual writing is done by writeProducts.  This keeps all the code below
+-- pure, and since the data sets involved are relatively small, performance is
+-- not a critical issue.
+
+type TypeMap   = M.Map String String
+data HscOutput = HscOutput [String] [String] TypeMap
+type Output    = State HscOutput
+
+newHscState :: HscOutput
+newHscState = HscOutput [] [] M.empty
+
+appendHsc :: String -> Output ()
+appendHsc hsc = do
+  HscOutput hscs xs types <- get
+  put $ HscOutput (hscs ++ [hsc]) xs types
+
+appendHelper :: String -> Output ()
+appendHelper helperc = do
+  HscOutput xs helpercs types <- get
+  put $ HscOutput xs (helpercs ++ [helperc]) types
+
+defineType :: String -> String -> Output ()
+defineType key value = do
+  HscOutput xs ys types <- get
+  put $ HscOutput xs ys (M.insert key value types)
+
+lookupType :: String -> Output (Maybe String)
+lookupType key = do
+  HscOutput _ _ types <- get
+  return $ M.lookup key types
+
+-- Now we are ready to parse the C code from the preprocessed input stream,
+-- located in the given file and starting at the specified position.  The
+-- result of a parse is a list of global declarations, so filter the list down
+-- to those occurring in the target file, and then print the declarations in
+-- Bindings-DSL format.
+
+parseCFile :: InputStream -> FilePath -> Position -> Output ()
+parseCFile stream fileName pos =
+  case parseC stream pos of
+    Left err -> error $ "Failed to compile: " ++ show err
+    Right (CTranslUnit decls _) -> generateHsc decls
+
+  where
+    generateHsc :: [CExtDecl] -> Output ()
+    generateHsc = traverse_ (appendNode fileName)
+
+declInFile :: FilePath -> CExtDecl -> Bool
+declInFile fileName = (fileName ==) . infoFile . declInfo
+
+infoFile :: NodeInfo -> String
+infoFile = posFile . posOfNode
+
+declInfo :: CExtDecl -> NodeInfo
+declInfo (CDeclExt (CDecl _ _ info))       = info
+declInfo (CFDefExt (CFunDef _ _ _ _ info)) = info
+declInfo (CAsmExt _ info)                  = info
+
+-- These are the top-level printing routines.  We are only interested in
+-- declarations and function defitions (which almost always means inline
+-- functions if the target file is a header file).
+--
+-- We will end up printing the following constructs:
+--
+--   - Structure definitions
+--   - Opaque types (i.e., forward declarations of pointer type)
+--   - Enums
+--   - Extern Functions
+--   - Inline Functions
+
+appendNode :: FilePath -> CExtDecl -> Output ()
+
+appendNode fp dx@(CDeclExt (CDecl declSpecs items _)) =
+  for_ items $ \(declrtr, _, _) -> do
+    for_ (splitDecl declrtr) $ \(d, ddrs, name) ->
+      case ddrs of
+        CFunDeclr (Right (_, _)) _ _ : _ ->
+          when (declInFile fp dx) $
+            appendFunc "#ccall" declSpecs d
+
+        _ -> do
+          when (declInFile fp dx) $ do
+            appendHsc $ "{- " ++ P.render (pretty dx) ++ " -}"
+            appendType declSpecs name
+
+          -- If the type is a typedef, record the equivalence so we can look
+          -- it up later
+          case head declSpecs of
+            CStorageSpec (CTypedef _) -> do
+              -- jww (2012-09-04): Types which are typedefs of functions
+              -- pointers are not working, since declSpecTypeName only gives
+              -- the function return type, not the function type
+              dname <- declSpecTypeName declSpecs
+              case dname of
+                "" -> return ()
+                _  -> defineType name dname
+            _ -> return ()
+
+  where splitDecl declrtr = do
+          -- Take advantage of the Maybe monad to save us some effort
+          d@(CDeclr ident ddrs _ _ _) <- declrtr
+          (Ident name _ _)            <- ident
+          return (d, ddrs, name)
+
+appendNode fp dx@(CFDefExt (CFunDef declSpecs declrtr _ _ _)) =
+  -- Assume functions defined in headers are inline functions
+  when (declInFile fp dx) $ do
+    appendFunc "#cinline" declSpecs declrtr
+
+    case declrtr of
+      (CDeclr ident ddrs _ _ _) ->
+        for_ ident $ \(Ident name _ _) ->
+          case head ddrs of
+            (CFunDeclr (Right (decls, _)) _ _) -> do
+              let argsList =
+                    concat . intersperse ", " . map (P.render . pretty) $ decls
+              retType <- derDeclrTypeName' True declSpecs (tail ddrs)
+              if retType /= ""
+                then appendHelper $ "BC_INLINE" ++ show (length decls)
+                                 ++ "(" ++ name ++ ", " ++ argsList
+                                 ++ ", " ++ retType ++ ")"
+                else appendHelper $ "BC_INLINE" ++ show (length decls)
+                                 ++ "VOID(" ++ name ++ ", " ++ argsList ++ ")"
+            _ -> return ()
+
+appendNode _ (CAsmExt _ _) = return ()
+
+-- Print out a function as #ccall or #cinline.  The syntax is the same for
+-- both externs and inlines, except that we want to do extra work for inline
+-- and create a helper file with some additional macros.
+
+appendFunc :: String -> [CDeclarationSpecifier a] -> CDeclarator a -> Output ()
+appendFunc marker declSpecs (CDeclr ident ddrs _ _ _) = do
+  retType  <- derDeclrTypeName declSpecs (tail ddrs)
+  argTypes <- sequence $ getArgTypes (head ddrs)
+
+  let name' = nameFromIdent ident
+      tmpl  = "$marker$ $name$ , $argTypes;separator=' -> '$ -> IO ($retType$)"
+      code  = newSTMP tmpl
+      -- I have to this separately since argTypes :: [String]
+      code' = setAttribute "argTypes" argTypes code
+      vars  = [ ("marker",  marker)
+              , ("name",    name')
+              , ("retType", retType) ]
+
+  appendHsc $ toString $ setManyAttrib vars code'
+
+  where
+    getArgTypes (CFunDeclr (Right (decls, _)) _ _) = map cdeclTypeName decls
+    getArgTypes _ = []
+
+    nameFromIdent :: Maybe Ident -> String
+    nameFromIdent name = case name of
+      Just (Ident n _ _) -> n
+      _ -> "<no name>"
+
+appendType :: [CDeclarationSpecifier a] -> String -> Output ()
+appendType declSpecs declrName = traverse_ appendType' declSpecs
+  where
+    appendType' (CTypeSpec (CSUType (CStruct _ ident decls _ _) _)) = do
+      let name' = identName ident
+      when (isNothing decls) $
+        appendHsc $ "#opaque_t " ++ name'
+
+      for_ decls $ \xs -> do
+        appendHsc $ "#starttype " ++ name'
+        for_ xs $ \x ->
+          for_ (cdeclName x) $ \declName -> do
+            tname <- cdeclTypeName x
+            appendHsc $ "#field " ++ declName ++ " , " ++ tname
+        appendHsc "#stoptype"
+
+    appendType' (CTypeSpec (CEnumType (CEnum ident defs _ _) _)) = do
+      let name' = identName ident
+      appendHsc $ "#integral_t " ++ name'
+
+      for_ defs $ \ds ->
+        for_ ds $ \((Ident name _ _), _) -> do
+          appendHsc $ "#num " ++ name
+
+    appendType' _ = return ()
+
+    identName ident = case ident of
+                        Nothing -> declrName
+                        Just (Ident name _ _) -> name
+
+-- The remainder of this file is some hairy code for turning various
+-- constructs into Bindings-DSL type names, such as turning "int ** foo" into
+-- the type name "Ptr (Ptr CInt)".
+
+data Signedness = None | Signed | Unsigned deriving (Eq, Show, Enum)
+
+cdeclName :: CDeclaration a -> Maybe String
+cdeclName (CDecl _ more _) =
+  case more of
+    (Just (CDeclr (Just (Ident name _ _)) _ _ _ _), _, _) : _ -> Just name
+    _ -> Nothing
+
+cdeclTypeName :: CDeclaration a -> Output String
+cdeclTypeName (CDecl declSpecs more _) =
+  case more of
+    (Just x, _, _) : _ -> declrTypeName declSpecs x
+    _                  -> declSpecTypeName declSpecs
+
+declSpecTypeName :: [CDeclarationSpecifier a] -> Output String
+declSpecTypeName = flip derDeclrTypeName []
+
+declrTypeName :: [CDeclarationSpecifier a] -> CDeclarator a -> Output String
+declrTypeName declSpecs (CDeclr _ ddrs _ _ _) = derDeclrTypeName declSpecs ddrs
+
+derDeclrTypeName :: [CDeclarationSpecifier a] -> [CDerivedDeclarator a]
+                 -> Output String
+derDeclrTypeName = derDeclrTypeName' False
+
+derDeclrTypeName' :: Bool -> [CDeclarationSpecifier a] -> [CDerivedDeclarator a]
+                  -> Output String
+derDeclrTypeName' cStyle declSpecs ddrs =
+  applyPointers <$> fullTypeName' None declSpecs <*> pure ddrs
+  where
+    fullTypeName' :: Signedness -> [CDeclarationSpecifier a] -> Output String
+    fullTypeName' _ []     = return ""
+    fullTypeName' s (x:xs) =
+      case x of
+        CTypeSpec (CSignedType _) -> fullTypeName' Signed xs
+        CTypeSpec (CUnsigType _)  -> fullTypeName' Unsigned xs
+        CTypeSpec tspec           -> if cStyle
+                                     then cTypeName tspec s
+                                     else typeName tspec s
+        _                         -> fullTypeName' s xs
+
+    applyPointers :: String -> [CDerivedDeclarator a] -> String
+    applyPointers baseType [] = baseType
+    applyPointers baseType (x:[]) =
+      case x of
+        CPtrDeclr _ _ ->
+          if cStyle
+          then if baseType == ""
+               then "void *"
+               else baseType ++ " *"
+          else if baseType == ""
+               then "Ptr ()"
+               else "Ptr " ++ baseType
+        _ -> ""
+    applyPointers baseType (x:xs) =
+      case x of
+        CPtrDeclr _ _ ->
+          if cStyle
+          then applyPointers baseType xs ++ " *"
+          else "Ptr (" ++ applyPointers baseType xs ++ ")"
+        _ -> ""
+
+-- Simple translation from C types to Foreign.C.Types types.  We represent
+-- Void as the empty string so that returning void becomes IO (), and passing
+-- a void star becomes Ptr ().
+
+typeName :: CTypeSpecifier a -> Signedness -> Output String
+
+typeName (CVoidType _) _   = return $ ""
+typeName (CFloatType _) _  = return $ "CFloat"
+typeName (CDoubleType _) _ = return $ "CDouble"
+typeName (CBoolType _) _   = return $ "CInt"
+
+typeName (CCharType _) s   = case s of
+                               Signed   -> return $ "CSChar"
+                               Unsigned -> return $ "CUChar"
+                               _        -> return $ "CChar"
+typeName (CShortType _) s  = case s of
+                               Signed   -> return $ "CShort"
+                               Unsigned -> return $ "CUShort"
+                               _        -> return $ "CShort"
+typeName (CIntType _) s    = case s of
+                               Signed   -> return $ "CInt"
+                               Unsigned -> return $ "CUInt"
+                               _        -> return $ "CInt"
+typeName (CLongType _) s   = case s of
+                               Signed   -> return $ "CLong"
+                               Unsigned -> return $ "CULong"
+                               _        -> return $ "CLong"
+
+typeName (CTypeDef (Ident name _ _) _) _ = do
+  definition <- lookupType name
+  return $ fromMaybe ("<" ++ name ++ ">") definition
+
+typeName (CComplexType _) _  = return $ ""
+typeName (CSUType _ _) _     = return $ ""
+typeName (CEnumType _ _) _   = return $ ""
+typeName (CTypeOfExpr _ _) _ = return $ ""
+typeName (CTypeOfType _ _) _ = return $ ""
+
+typeName _ _ = return $ ""
+
+-- Translation from C back to C.  Needed because there's no good way to pretty
+-- print a function's return type (including pointers on the declarator) in
+-- language-c.
+
+cTypeName :: CTypeSpecifier a -> Signedness -> Output String
+
+cTypeName (CVoidType _) _   = return $ ""
+cTypeName (CFloatType _) _  = return $ "float"
+cTypeName (CDoubleType _) _ = return $ "double"
+cTypeName (CBoolType _) _   = return $ "int"
+
+cTypeName (CCharType _) s   = case s of
+                               Signed   -> return $ "signed char"
+                               Unsigned -> return $ "unsigned char"
+                               _        -> return $ "char"
+cTypeName (CShortType _) s  = case s of
+                               Signed   -> return $ "signed short"
+                               Unsigned -> return $ "unsigned short"
+                               _        -> return $ "hort"
+cTypeName (CIntType _) s    = case s of
+                               Signed   -> return $ "signed int"
+                               Unsigned -> return $ "unsigned int"
+                               _        -> return $ "int"
+cTypeName (CLongType _) s   = case s of
+                               Signed   -> return $ "signed long"
+                               Unsigned -> return $ "unsigned long"
+                               _        -> return $ "long"
+
+cTypeName (CTypeDef (Ident name _ _) _) _ = do
+  definition <- lookupType name
+  return $ fromMaybe name definition
+
+cTypeName (CComplexType _) _  = return $ ""
+cTypeName (CSUType _ _) _     = return $ ""
+cTypeName (CEnumType _ _) _   = return $ ""
+cTypeName (CTypeOfExpr _ _) _ = return $ ""
+cTypeName (CTypeOfType _ _) _ = return $ ""
+
+cTypeName _ _ = return $ ""
+
+-- parseFile "/usr/bin/gcc" ["-U__BLOCKS__", "/Users/johnw/src/hlibgit2/libgit2/include/git2/types.h"]
+
+-- c2hsc.hs
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+Converts C API header files to `.hsc` and `.hsc.helper.c` files
+
+    Usage: c2hsc <Lib Prefix> [cpp options...] <FILE>.h
+
+This will create `<FILE>.hsc`, and `<FILE>.hsc.helper.c` if the header file
+contains inline functions.
+
+For example, in `hlibgit2` on the Mac I'm using:
+
+    c2hsc Bindings.Libgit2 -U__BLOCKS__ libgit2/include/git2/tree.h
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/c2hsc.cabal b/c2hsc.cabal
new file mode 100644
--- /dev/null
+++ b/c2hsc.cabal
@@ -0,0 +1,35 @@
+Name: c2hsc
+
+Version:  0.1.0
+Synopsis: Convert C API header files to .hsc and .hsc.helper.c files
+
+Description: Convert C API header files to .hsc and .hsc.helper.c files
+
+Homepage:           https://github.com/jwiegley/c2hsc
+License:            BSD3
+License-file:       LICENSE
+Author:             John Wiegley
+Maintainer:         John Wiegley <johnw@newartisans.com>
+Category:           Utilities
+Build-type:         Simple
+Cabal-version:      >= 1.8
+
+Extra-Source-Files: README.md
+
+Executable c2hs
+    Main-is: Main.hs
+    Ghc-options: -Wall
+
+    Build-depends: base >= 4 && < 5
+                 , mtl >= 1.1 && < 2.1
+                 , containers
+                 , transformers
+                 , directory
+                 , language-c
+                 , HStringTemplate
+                 , pretty
+                 , filepath
+
+Source-repository head
+  type:     git
+  location: https://github.com/jwiegley/c2hsc
