{-# LANGUAGE OverloadedStrings, TemplateHaskell, DeriveDataTypeable #-} import Control.Monad import Data.List import Language.Haskell.TH import DBus import DBus.Client hiding (interfaceName) import qualified DBus.Introspection as I import DBus.TH.EDSL as TH import DBus.TH.Introspection import System.Console.CmdArgs import System.IO data Options = Options { moduleName :: String, outputFile :: String, system :: Bool, serviceName :: String, objectPath :: String, interfaceName :: String, dynamicObject :: Bool } deriving (Data, Typeable, Show, Eq) options = Options { moduleName = "Interface" &= typ "NAME" &= name "module" &= help "Haskell module name", outputFile = "-" &= typFile &= name "output" &= help "Output file", system = False &= help "Use system bus instead of sesion bus", serviceName = def &= typ "SERVICE.NAME" &= argPos 0 &= opt ("" :: String), objectPath = def &= typ "/PATH/TO/OBJECT" &= argPos 1 &= opt ("" :: String), interfaceName = def &= typ "INTERFACE.NAME" &= argPos 2 &= opt ("" :: String), dynamicObject = def &= name "dynamic" &= help "If specified - generated functions will get object path as 2nd argument" } &= help "Introspect specified DBus object/interface and generate TemplateHaskell source for calling all functions from Haskell" &= program "dbus-introspect-hs" &= summary "dbus-introspect-hs program" withOutFile :: FilePath -> (Handle -> IO a) -> IO a withOutFile "-" fn = fn stdout withOutFile path fn = withFile path WriteMode fn main :: IO () main = do opts <- cmdArgs options dbus <- if system opts then connectSystem else connectSession services <- if serviceName opts == "" then do ss <- listNames dbus case ss of Nothing -> fail $ "Can't obtain list of services" Just list -> return $ map busName_ list else return [busName_ $ serviceName opts] withOutFile (outputFile opts) $ \h -> do hPutStrLn h $ header (moduleName opts) forM_ services $ \service -> do hPutStrLn h $ "-- Service " ++ formatBusName service objects <- if objectPath opts == "" then do obs <- getServiceObjects dbus service "/" return $ map I.objectPath obs else return [objectPath_ $ objectPath opts] forM_ objects $ \object -> do ob <- introspect dbus service object forM_ (I.objectInterfaces ob) $ \iface -> do let ifaceName = formatInterfaceName (I.interfaceName iface) useIface = case interfaceName opts of "" -> True name -> name == ifaceName when useIface $ do hPutStrLn h $ "-- Interface " ++ ifaceName funcs <- forM (I.interfaceMethods iface) $ \m -> do -- hPutStrLn h $ " -- Method: " ++ let methodName = formatMemberName (I.methodName m) case method2function m of Left err -> do return [ "-- Error: method " ++ methodName ++ ": " ++ err ] Right fn -> return [ pprintFunc fn ] let path = if dynamicObject opts then Nothing else Just (formatObjectPath object) hPutStrLn h $ pprintInterface (formatBusName service) path ifaceName (concat funcs)