packages feed

xcb-types (empty) → 0.1.0

raw patch · 8 files changed

+741/−0 lines, 8 filesdep +basedep +mtldep +prettysetup-changed

Dependencies added: base, mtl, pretty, xml

Files

+ Data/XCB.hs view
@@ -0,0 +1,23 @@+-- |+-- Module    :  Data.XCB+-- Copyright :  (c) Antoine Latter 2008+-- License   :  BSD3+--+-- Maintainer:  Antoine Latter <aslatter@gmail.com>+-- Stability :  provisional+-- Portability: portable+--+-- The 'Data.XCB' module can parse the contents of the xcb-proto+-- XML files into Haskell data structures.+--+-- Pretty-printers are provided to aid in the debugging - they do+-- not pretty-print to XML, but to a custom human-readable format.+module Data.XCB+    (module Data.XCB.Types+    ,module Data.XCB.FromXML+    ,module Data.XCB.Pretty+    ) where++import Data.XCB.Types+import Data.XCB.FromXML+import Data.XCB.Pretty
+ Data/XCB/FromXML.hs view
@@ -0,0 +1,401 @@+-- |+-- Module    :  Data.XCB.FromXML+-- Copyright :  (c) Antoine Latter 2008+-- License   :  BSD3+--+-- Maintainer:  Antoine Latter <aslatter@gmail.com>+-- Stability :  provisional+-- Portability: portable+--+-- Handls parsing the data structures from XML files.+--+-- In order to support copying events and errors across module+-- boundaries, all modules which may have cross-module event copies and+-- error copies must be parsed at once.+--+-- There is no provision for preserving the event copy and error copy+-- declarations - the copies are handled during parsing.+module Data.XCB.FromXML(fromFiles+                       ,fromStrings+                       ) where++import Data.XCB.Types+import Data.XCB.Pretty+import Data.XCB.Utils++import Text.XML.Light++import Data.List as List+import Data.Maybe+import Data.Monoid++import Control.Monad+import Control.Monad.Reader++import Control.Applicative++-- |Process the listed XML files.+-- Any files which fail to parse are silently dropped.+-- Any declaration in an XML file which fail to parse are+-- silently dropped.+fromFiles :: [FilePath] -> IO [XHeader]+fromFiles xs = do+  strings <- sequence $ map readFile xs+  return $ fromStrings strings++-- |Process the strings as if they were XML files.+-- Any files which fail to parse are silently dropped.+-- Any declaration in an XML file which fail to parse are+-- silently dropped.+fromStrings :: [String] -> [XHeader]+fromStrings xs =+   let rs = mapAlt fromString xs+       Just headers = runReaderT rs headers+   in headers ++-- The 'Parse' monad.  Provides the name of the+-- current module, and a list of all of the modules.+type Parse = ReaderT ([XHeader],Name) Maybe++-- operations in the 'Parse' monad++localName :: Parse Name+localName = snd `liftM` ask++allModules :: Parse [XHeader]+allModules = fst `liftM` ask++-- a generic function for looking up something from+-- a named XHeader.+--+-- this implements searching both the current module and+-- the xproto module if the name is not specified.+lookupThingy :: ([XDecl] -> Maybe a)+             -> (Maybe Name)+             -> Parse (Maybe a)+lookupThingy f Nothing = do+  lname <- localName+  liftM2 mplus (lookupThingy f $ Just lname)+               (lookupThingy f $ Just "xproto") -- implicit xproto import+lookupThingy f (Just mname) = do+  xs <- allModules+  return $ do+    x <- findXHeader mname xs+    f $ xheader_decls x++-- lookup an event declaration by name.+lookupEvent :: Maybe Name -> Name -> Parse (Maybe EventDetails)+lookupEvent mname evname = flip lookupThingy mname $ \decls ->+                 findEvent evname decls++-- lookup an error declaration by name.+lookupError :: Maybe Name -> Name -> Parse (Maybe ErrorDetails)+lookupError mname ername = flip lookupThingy mname $ \decls ->+                 findError ername decls++findXHeader :: Name -> [XHeader] -> Maybe XHeader+findXHeader name = List.find $ \ x -> xheader_header x == name++findError :: Name -> [XDecl] -> Maybe ErrorDetails+findError pname xs =+      case List.find f xs of+        Nothing -> Nothing+        Just (XError name code elems) -> Just $ ErrorDetails name code elems+    where  f (XError name _ _) | name == pname = True+           f _ = False +                                       +findEvent :: Name -> [XDecl] -> Maybe EventDetails+findEvent pname xs = +      case List.find f xs of+        Nothing -> Nothing+        Just (XEvent name code elems) -> Just $ EventDetails name code elems+   where f (XEvent name _ _) | name == pname = True+         f _ = False ++data EventDetails = EventDetails Name Int [StructElem]+data ErrorDetails = ErrorDetails Name Int [StructElem]++---++-- extract a single XHeader from a single XML document+fromString :: String -> ReaderT [XHeader] Maybe XHeader+fromString str = do+  el@(Element qname ats cnt _) <- lift $ parseXMLDoc str+  guard $ el `named` "xcb"+  header <- el `attr` "header"+  let name = el `attr` "extension-name"+      xname = el `attr` "extension-xname"+      maj_ver = el `attr` "major-version" >>= readM+      min_ver = el `attr` "minor-version" >>= readM+      multiword = el `attr` "extension-multiword" >>= readM . ensureUpper+  decls <- withReaderT (\r -> (r,header)) $ extractDecls cnt+  return $ XHeader {xheader_header = header+                   ,xheader_xname = xname+                   ,xheader_name = name+                   ,xheader_multiword = multiword+                   ,xheader_major_version = maj_ver+                   ,xheader_minor_version = min_ver+                   ,xheader_decls = decls+                   }++-- attempts to extract declarations from XML content, discarding failures.+extractDecls :: [Content] -> Parse [XDecl]+extractDecls = mapAlt declFromElem . onlyElems++-- attempt to extract a module declaration from an XML element+declFromElem :: Element -> Parse XDecl+declFromElem elem +    | elem `named` "request" = xrequest elem+    | elem `named` "event"   = xevent elem+    | elem `named` "eventcopy" = xevcopy elem+    | elem `named` "error" = xerror elem+    | elem `named` "errorcopy" = xercopy elem+    | elem `named` "struct" = xstruct elem+    | elem `named` "union" = xunion elem+    | elem `named` "xidtype" = xidtype elem+    | elem `named` "xidunion" = xidunion elem+    | elem `named` "typedef" = xtypedef elem+    | elem `named` "enum" = xenum elem+    | elem `named` "import" = ximport elem+    | otherwise = mzero+++ximport :: Element -> Parse XDecl+ximport = return . XImport . strContent++xenum :: Element -> Parse XDecl+xenum elem = do+  nm <- elem `attr` "name"+  fields <- mapAlt enumField $ elChildren elem+  guard $ not $ null fields+  return $ XEnum nm fields++enumField :: Element -> Parse EnumElem+enumField elem = do+  guard $ elem `named` "item"+  name <- elem `attr` "name"+  let expr = firstChild elem >>= expression+  return $ EnumElem name expr++xrequest :: Element -> Parse XDecl+xrequest elem = do+  nm <- elem `attr` "name"+  code <- elem `attr` "opcode" >>= readM+  fields <- mapAlt structField $ elChildren elem+  let reply = getReply elem+  guard $ not (null fields) || not (isNothing reply)+  return $ XRequest nm code fields reply++getReply :: Element -> Maybe XReply+getReply elem = do+  childElem <- unqual "reply" `findChild` elem+  let fields = mapMaybe structField $ elChildren childElem+  guard $ not $ null fields+  return fields++xevent :: Element -> Parse XDecl+xevent elem = do+  name <- elem `attr` "name"+  number <- elem `attr` "number" >>= readM+  fields <- mapAlt structField $ elChildren elem+  guard $ not $ null fields+  return $ XEvent name number fields++xevcopy :: Element -> Parse XDecl+xevcopy elem = do+  name <- elem `attr` "name"+  number <- elem `attr` "number" >>= readM+  ref <- elem `attr` "ref"+  -- do we have a qualified ref?+  let (mname,evname) = splitRef ref+  details <- lookupEvent mname evname +  return $ XEvent name number $ case details of+               Nothing -> error $ "Unresolved event: " ++ show mname ++ " " ++ ref+               Just (EventDetails _ _ x) -> x++-- we need to do string processing to distinguish qualified from+-- unqualified types.+mkType :: String -> Type+mkType str =+    let (mname, name) = splitRef str+    in case mname of+         Just mod -> QualType mod name+         Nothing  -> UnQualType name++splitRef :: Name -> (Maybe Name, Name)+splitRef ref = case split ':' ref of+                 (x,"") -> (Nothing, x)+                 (a, b) -> (Just a, b)++-- |Neither returned string contains the first occurance of the+-- supplied Char.+split :: Char -> String -> (String, String)+split c xs = go xs+    where go [] = ([],[])+          go (x:xs) | x == c = ([],xs)+                    | otherwise = +                        let (lefts, rights) = go xs+                        in (x:lefts,rights)+                 ++xerror :: Element -> Parse XDecl+xerror elem = do+  name <- elem `attr` "name"+  number <- elem `attr` "number" >>= readM+  fields <- mapAlt structField $ elChildren elem+  guard $ not $ null fields+  return $ XError name number fields+++xercopy :: Element -> Parse XDecl+xercopy elem = do+  name <- elem `attr` "name"+  number <- elem `attr` "number" >>= readM+  ref <- elem `attr` "ref"+  let (mname, ername) = splitRef ref+  details <- lookupError mname ername+  return $ XError name number $ case details of+               Nothing -> error $ "Unresolved error: " ++ show mname ++ " " ++ ref+               Just (ErrorDetails _ _ x) -> x++xstruct :: Element -> Parse XDecl+xstruct elem = do+  name <- elem `attr` "name"+  fields <- mapAlt structField $ elChildren elem+  guard $ not $ null fields+  return $ XStruct name fields++xunion :: Element -> Parse XDecl+xunion elem = do+  name <- elem `attr` "name"+  fields <- mapAlt structField $ elChildren elem+  guard $ not $ null fields+  return $ XUnion name fields++xidtype :: Element -> Parse XDecl+xidtype elem = liftM XidType $ elem `attr` "name"++xidunion :: Element -> Parse XDecl+xidunion elem = do+  name <- elem `attr` "name"+  let types = mapMaybe xidUnionElem $ elChildren elem+  guard $ not $ null types+  return $ XidUnion name types++xidUnionElem :: Element -> Maybe XidUnionElem+xidUnionElem elem = do+  guard $ elem `named` "type"+  return $ XidUnionElem $ mkType $ strContent elem++xtypedef :: Element -> Parse XDecl+xtypedef elem = do+  oldtyp <- liftM mkType $ elem `attr` "oldname"+  newname <- elem `attr` "newname"+  return $ XTypeDef newname oldtyp+++structField :: MonadPlus m => Element -> m StructElem+structField elem+    | elem `named` "field" = do+        typ <- liftM mkType $ elem `attr` "type"+        name <- elem `attr` "name"+        return $ SField name typ++    | elem `named` "pad" = do+        bytes <- elem `attr` "bytes" >>= readM+        return $ Pad bytes++    | elem `named` "list" = do+        typ <- liftM mkType $ elem `attr` "type"+        name <- elem `attr` "name"+        let expr = firstChild elem >>= expression+        return $ List name typ expr++    | elem `named` "valueparam" = do+        mask_typ <- liftM mkType $ elem `attr` "value-mask-type"+        mask_name <- elem `attr` "value-mask-name"+        list_name <- elem `attr` "value-list-name"+        return $ ValueParam mask_typ mask_name list_name++    | elem `named` "exprfield" = do+        typ <- liftM mkType $ elem `attr` "type"+        name <- elem `attr` "name"+        expr <- firstChild elem >>= expression+        return $ ExprField name typ expr++    | elem `named` "reply" = fail "" -- handled separate++    | otherwise = let name = elName elem+                  in error $ "I don't know what to do with structelem "+ ++ show name++expression :: MonadPlus m => Element -> m Expression+expression elem | elem `named` "fieldref"+                    = return $ FieldRef $ strContent elem+                | elem `named` "value"+                    = Value `liftM` readM (strContent elem)+                | elem `named` "bit"+                    = Bit `liftM` do+                        n <- readM (strContent elem)+                        guard $ n >= 0+                        return n+                | elem `named` "op" = do+                    binop <- elem `attr` "op" >>= toBinop+                    [exprLhs,exprRhs] <- mapM expression $ elChildren elem+                    return $ Op binop exprLhs exprRhs+++toBinop :: MonadPlus m => String -> m Binop+toBinop "+"  = return Add+toBinop "-"  = return Sub+toBinop "*"  = return Mult+toBinop "/"  = return Div+toBinop "&"  = return And+toBinop "&amp;" = return And+toBinop ">>" = return RShift+toBinop _ = mzero+++++----+----+-- Utility functions+----+----++firstChild :: MonadPlus m => Element -> m Element+firstChild = listToM . elChildren++listToM :: MonadPlus m => [a] -> m a+listToM [] = mzero+listToM (x:xs) = return x++named :: Element -> String -> Bool+named (Element qname _ _ _) name | qname == unqual name = True+named _ _ = False++attr :: MonadPlus m => Element -> String -> m String+(Element _ xs _ _) `attr` name = case List.find p xs of+      Just (Attr _ res) -> return res+      _ -> mzero+    where p (Attr qname _) | qname == unqual name = True+          p _ = False++-- adapted from Network.CGI.Protocol+readM :: (MonadPlus m, Read a) => String -> m a+readM = liftM fst . listToM . reads++maybeRead :: Read a => String -> Maybe a+maybeRead = readM++-- In retorspect maybe I should've gone with MonadPlus, but the+-- code is already written so I guess I need these instances.++instance (Alternative f, Monad f) => Alternative (ReaderT r f) where+    empty = ReaderT $ \r -> empty+    m1 <|> m2 = ReaderT $ \r -> (runReaderT m1 r) <|> (runReaderT m2 r)++instance (Applicative f, Monad f) => Applicative (ReaderT r f) where+    pure a = ReaderT $ \_ -> pure a+    mf <*> m = ReaderT $ \r -> (runReaderT mf r) <*> (runReaderT m r)
+ Data/XCB/Pretty.hs view
@@ -0,0 +1,131 @@+{-# LANGUAGE TypeSynonymInstances #-}++-- |+-- Module    :  Data.XCB.Pretty+-- Copyright :  (c) Antoine Latter 2008+-- License   :  BSD3+--+-- Maintainer:  Antoine Latter <aslatter@gmail.com>+-- Stability :  provisional+-- Portability: portable - requires TypeSynonymInstances+--+-- Pretty-printers for the tyes declared in this package.+-- This does NOT ouput XML - it produces human-readable information+-- intended to aid in debugging.+module Data.XCB.Pretty where++import Data.XCB.Types++import Text.PrettyPrint.HughesPJ++-- |Minimal complete definition:+--+-- One of 'pretty' or 'toDoc'.+class Pretty a where+    toDoc :: a -> Doc+    pretty :: a -> String++    pretty = show . toDoc+    toDoc = text . pretty++-- Builtin types++instance Pretty String where+    pretty = show++instance Pretty Int where+    pretty = show++instance Pretty a => Pretty (Maybe a) where+    toDoc Nothing = empty+    toDoc (Just a) = toDoc a++    pretty Nothing = ""+    pretty (Just a) = pretty a++-- Simple stuff++instance Pretty XidUnionElem where+    pretty = show++instance Pretty Binop where+    pretty Add  = "+"+    pretty Sub  = "-"+    pretty Mult = "*"+    pretty Div  = "/"+    pretty RShift = ">>"+    pretty And = "&"++instance Pretty EnumElem where+    toDoc (EnumElem name expr)+        = text name <> char ':' <+> toDoc expr++instance Pretty Type where+    toDoc (UnQualType name) = text name+    toDoc (QualType mod name) = text mod <> char '.' <> text name++-- More complex stuff++instance Pretty Expression where+    toDoc (Value n) = toDoc n+    toDoc (Bit n) = text "2^" <> toDoc n+    toDoc (FieldRef ref) = char '$' <> text ref+    toDoc (Op binop exprL exprR)+        = parens $ hsep [toDoc exprL+                        ,toDoc binop+                        ,toDoc exprR+                        ]++instance Pretty StructElem where+    toDoc (Pad n) = braces $ toDoc n <+> text "bytes"+    toDoc (List nm typ len)+        = text nm <+> text "::" <+> brackets (toDoc typ) <+> toDoc len+    toDoc (SField nm typ) = hsep [text nm+                                 ,text "::"+                                 ,toDoc typ+                                 ]+    toDoc (ExprField nm typ expr)+          = parens (text nm <+> text "::" <+> toDoc typ)+            <+> toDoc expr+    toDoc (ValueParam typ mname lname)+        = text "Valueparam" <+>+          text "::" <+>+          hsep (punctuate (char ',') [toDoc typ+                                     ,text mname+                                     ,text lname+                                     ])++instance Pretty XDecl where+    toDoc (XStruct nm elems) =+        hang (text "Struct:" <+> text nm) 2 $ vcat $ map toDoc elems+    toDoc (XTypeDef nm typ) = hsep [text "TypeDef:"+                                    ,text nm+                                    ,text "as"+                                    ,toDoc typ+                                    ]+    toDoc (XEvent nm n elems) =+        hang (text "Event:" <+> text nm <> char ',' <> toDoc n) 2 $+             vcat $ map toDoc elems+    toDoc (XRequest nm n elems mrep) = +        (hang (text "Request:" <+> text nm <> char ',' <> toDoc n) 2 $+             vcat $ map toDoc elems)+         $$ case mrep of+             Nothing -> empty+             Just reply ->+                 hang (text "Reply:" <+> text nm <> char ',' <> toDoc n) 2 $+                      vcat $ map toDoc reply+    toDoc (XidType nm) = text "XID:" <+> text nm+    toDoc (XidUnion nm elems) = +        hang (text "XID" <+> text "Union:" <+> text nm) 2 $+             vcat $ map toDoc elems+    toDoc (XEnum nm elems) =+        hang (text "Enum:" <+> text nm) 2 $ vcat $ map toDoc elems+    toDoc (XUnion nm elems) = +        hang (text "Union:" <+> text nm) 2 $ vcat $ map toDoc elems+    toDoc (XImport nm) = text "Import:" <+> text nm+    toDoc (XError nm n elems) = +        hang (text "Error:" <+> text nm) 2 $ vcat $ map toDoc elems++instance Pretty XHeader where+    toDoc xhd = text (xheader_header xhd) $$+                (vcat $ map toDoc (xheader_decls xhd))
+ Data/XCB/Types.hs view
@@ -0,0 +1,99 @@++-- |+-- Module    :  Data.XCB.Types+-- Copyright :  (c) Antoine Latter 2008+-- License   :  BSD3+--+-- Maintainer:  Antoine Latter <aslatter@gmail.com>+-- Stability :  provisional+-- Portability: portable+--+-- Defines types inteneded to be equivalent to the schema used by+-- the XCB project in their XML protocol description.+--+++module Data.XCB.Types where+++import qualified Data.List as L+import Control.Monad++-- 'xheader_header' is the name gauranteed to exist, and is used in+-- imports and in type qualifiers.+--+-- 'xheader_name' is the InterCaps name, and should be prefered in the naming+-- of types, functions and haskell modules when available.+-- |This is what a single XML file maps to.  It contains some meta-data+-- then declarations.+data XHeader = XHeader {xheader_header :: Name -- ^Name of module.  Used in the other modules as a reference.+                       ,xheader_xname :: Maybe Name  -- ^Name used to indentify extensions between the X client and server.+                       ,xheader_name :: Maybe Name -- ^InterCaps name.+                       ,xheader_multiword :: Maybe Bool+                       ,xheader_major_version :: Maybe Int+                       ,xheader_minor_version :: Maybe Int+                       ,xheader_decls :: [XDecl]  -- ^Declarations contained in this module.+                       }+ deriving (Show)++-- |The different types of declarations which can be made in one of the+-- XML files.+data XDecl = XStruct  Name [StructElem]+           | XTypeDef Name Type+           | XEvent Name Int [StructElem]+           | XRequest Name Int [StructElem] (Maybe XReply)+           | XidType  Name+           | XidUnion  Name [XidUnionElem]+           | XEnum Name [EnumElem]+           | XUnion Name [StructElem]+           | XImport Name+           | XError Name Int [StructElem]+ deriving (Show)++data StructElem = Pad Int+                | List Name Type (Maybe Expression)+                | SField Name Type+                | ExprField Name Type Expression+                | ValueParam Type MaskName ListName+ deriving (Show)++type Name = String+type XReply = [StructElem]+type Ref = String++-- |Types may include a reference to the containing module.+data Type = UnQualType Name+          | QualType Name Name+ deriving Show++type MaskName = Name+type ListName = Name++data ExInfo = ExInfo Name Name Version+ deriving (Show)++type Version = (String,String)++data XidUnionElem = XidUnionElem Type+ deriving (Show)++-- Should only ever have expressions of type 'Value' or 'Bit'.+data EnumElem = EnumElem Name (Maybe Expression)+ deriving (Show)++-- |Declarations may contain expressions from this small language+data Expression = Value Int  -- ^A literal value+                | Bit Int    -- ^A log-base-2 literal value+                | FieldRef String -- ^A reference to a field in the same declaration+                | Op Binop Expression Expression -- ^A binary opeation+ deriving (Show)++-- |Supported Binary operations.+data Binop = Add+           | Sub+           | Mult+           | Div+           | And+           | RShift+ deriving (Show)+
+ Data/XCB/Utils.hs view
@@ -0,0 +1,18 @@+module Data.XCB.Utils where++-- random utility functions++import Data.Char+import Control.Applicative++ensureUpper :: String -> String+ensureUpper [] = []+ensureUpper (x:xs) = (toUpper x) : xs++-- |Like mapMaybe, but for any Alternative.+-- Never returns 'empty', instead returns 'pure []'+mapAlt :: Alternative f => (a -> f b) -> [a] -> f [b]+mapAlt f xs = go xs+ where go [] = pure []+       go (y:ys) = pure (:) <*> f y <*> go ys+               <|> go ys
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Antoine Latter 2008++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 the author nor the names of other+      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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ xcb-types.cabal view
@@ -0,0 +1,37 @@+Name:         xcb-types+Version:      0.1.0+Cabal-Version:  >= 1.2+Synopsis:     Parses XML files used by the XCB project+Description:   This package provides types which mirror the structures+  used in the XCB code generation XML files.++  See project http://xcb.freedesktop.org/ for more information about the XCB+  project.++  The XML files describe the data-types, events and requests used by the+  X Protocol, and are used to auto-generate large parts of the XCB project.++ This package parses these XML files into Haskell data structures.++  If you want to do something with these XML descriptions but don't want+  to learn XSLT, this package should help.++License:      BSD3+License-file: LICENSE+Author:       Antoine Latter+Maintainer:   Antoine Latter <aslatter@gmail.com>++Build-type: Simple++Category: Data++Library++ Build-depends: base, xml, pretty, mtl+ Exposed-modules: Data.XCB,+                  Data.XCB.Types,+                  Data.XCB.Pretty,+                  Data.XCB.FromXML++ Other-modules:   Data.XCB.Utils+