-------------------------------------------------------------------------------- -- $Id: SwishCommands.hs,v 1.13 2003/12/11 19:11:07 graham Exp $ -- -- Copyright (c) 2003, G. KLYNE. All rights reserved. -- See end of this file for licence information. -------------------------------------------------------------------------------- -- | -- Module : SwishCommands -- Copyright : (c) 2003, Graham Klyne -- License : GPL V2 -- -- Maintainer : Graham Klyne -- Stability : provisional -- Portability : H98 -- -- SwishCommands: functions to deal with indivudual Swish command options. -- -------------------------------------------------------------------------------- module SwishCommands ( swishFormat , swishInput , swishOutput , swishMerge , swishCompare , swishScript ) where import SwishMonad ( SwishStateIO, SwishState(..) , setFormat, setGraph , modGraphs, modRulesets , setInfo, resetInfo, setError, resetError, setExitcode , emptyState , SwishFormat(..) , swishError , reportLines, reportLine ) import SwishScript ( parseScriptFromString ) import RDFGraph ( RDFGraph, merge ) import N3Formatter ( formatGraphAsShowS ) import N3Parser ( ParseResult(..), parseN3fromString ) -- import MiscHelpers import ErrorM( ErrorM(..) ) import IO ( Handle(..), openFile, IOMode(..) , hPutStr, hPutStrLn, hClose, hGetContents , hIsOpen, hIsReadable, hIsWritable , stdin, stdout, stderr, try ) import Control.Monad.Trans( MonadTrans(..) ) import Control.Monad.State ( MonadState(..), modify, gets , StateT(..), execStateT ) import Maybe ( Maybe(..), isJust, fromJust ) import Monad ( when ) import System ( ExitCode(..) ) ------------------------------------------------------------ -- Set file format to supplied value ------------------------------------------------------------ swishFormat :: SwishFormat -> SwishStateIO () swishFormat fmt = modify $ setFormat fmt ------------------------------------------------------------ -- Read graph from named file ------------------------------------------------------------ swishInput :: String -> SwishStateIO () swishInput fnam = do { maybegraph <- swishReadGraph fnam ; case maybegraph of Just g -> modify $ setGraph g otherwise -> return () } ------------------------------------------------------------ -- Merge graph from named file ------------------------------------------------------------ swishMerge :: String -> SwishStateIO () swishMerge fnam = do { maybegraph <- swishReadGraph fnam ; case maybegraph of Just g -> modify $ mergeGraph g otherwise -> return () } mergeGraph gr state = state { graph = newgr } where newgr = merge gr (graph state) ------------------------------------------------------------ -- Compare graph from named file ------------------------------------------------------------ swishCompare :: String -> SwishStateIO () swishCompare fnam = do { maybegraph <- swishReadGraph fnam ; case maybegraph of Just g -> compareGraph g otherwise -> return () } compareGraph :: RDFGraph -> SwishStateIO () compareGraph gr = do { oldgr <- gets graph ; let exitCode = if gr == oldgr then System.ExitSuccess else System.ExitFailure 1 ; modify $ setExitcode exitCode } ------------------------------------------------------------ -- Execute script from named file ------------------------------------------------------------ swishScript :: String -> SwishStateIO () swishScript fnam = do { scs <- swishReadScript fnam ; sequence_ (map swishCheckResult scs) } swishReadScript :: String -> SwishStateIO [SwishStateIO ()] swishReadScript fnam = do { maybefile <- swishOpenFile fnam ; case maybefile of Just (h,i) -> do { res <- swishParseScript fnam i ; lift $ hClose h ; return res } otherwise -> return [] } swishParseScript :: String -> String -> SwishStateIO [SwishStateIO ()] swishParseScript fnam inp = do { let base = if null fnam then Nothing else Just fnam ; let sres = parseScriptFromString base inp ; case sres of Error err -> do { swishError ("Script syntax error in file "++fnam++": "++err) 2 ; return [] } Result scs -> return scs } swishCheckResult :: SwishStateIO () -> SwishStateIO () swishCheckResult swishcommand = do { swishcommand ; er <- gets errormsg ; when (isJust er) $ do { swishError (fromJust er) 5 ; modify $ resetError } ; ms <- gets infomsg ; when (isJust ms) $ do { reportLine (fromJust ms) ; modify $ resetInfo } } ------------------------------------------------------------ -- Output graph to named file ------------------------------------------------------------ swishOutput :: String -> SwishStateIO () swishOutput fnam = do { maybehandleclose <- swishWriteFile fnam ; case maybehandleclose of Just (h,c) -> do { swishOutputGraph fnam h ; if c then lift $ hClose h else return () } otherwise -> return () } swishOutputGraph :: String -> Handle -> SwishStateIO () swishOutputGraph fnam hnd = do { fmt <- gets $ format ; case fmt of N3 -> swishFormatN3 fnam hnd otherwise -> swishError ("Unsupported file format: "++(show fmt)) 4 } swishFormatN3 :: String -> Handle -> SwishStateIO () swishFormatN3 fnam hnd = do { out <- gets $ formatGraphAsShowS . graph ; lift $ hPutStr hnd (out "") } ------------------------------------------------------------ -- Common input functions ------------------------------------------------------------ -- -- Keep the logic separate for reading file data and -- parsing it to an RDF graph value. swishReadGraph :: String -> SwishStateIO (Maybe RDFGraph) swishReadGraph fnam = do { maybefile <- swishOpenFile fnam ; case maybefile of Just (h,i) -> do { res <- swishParse fnam i ; lift $ hClose h ; return res } otherwise -> return Nothing } -- Open and read file, returning its handle and content, or Nothing -- WARNING: the handle must not be closed until input is fully evaluated swishOpenFile :: String -> SwishStateIO (Maybe (Handle,String)) swishOpenFile fnam = do { (hnd,hop) <- lift $ if null fnam then return (stdin,True) else do { o <- try (openFile fnam ReadMode) ; case o of Left e -> return (stdin,False) Right h -> return (h,True) } ; hrd <- lift $ hIsReadable hnd ; res <- if hop && hrd then do { ; fc <- lift $ hGetContents hnd ; return $ Just (hnd,fc) } else do { lift $ hClose hnd ; swishError ("Cannot read file: "++fnam) 3 ; return Nothing } ; return res } swishParse :: String -> String -> SwishStateIO (Maybe RDFGraph) swishParse fnam inp = do { fmt <- gets $ format ; case fmt of N3 -> swishParseN3 fnam inp otherwise -> do { swishError ("Unsupported file format: "++(show fmt)) 4 ; return Nothing } } swishParseN3 :: String -> String -> SwishStateIO (Maybe RDFGraph) swishParseN3 fnam inp = do { let pres = parseN3fromString inp ; case pres of Error err -> do { swishError ("N3 syntax error in file "++fnam++": "++err) 2 ; return Nothing } Result gr -> return $ Just gr } -- Open file for writing, returning its handle, or Nothing -- Also returned is a flag indicating whether or not the -- handled should be closed when writing is done (if writing -- to standard output, the handle should not be closed as the -- run-time system should deal with that). swishWriteFile :: String -> SwishStateIO (Maybe (Handle,Bool)) swishWriteFile fnam = do { (hnd,hop,cls) <- lift $ if null fnam then return (stdout,True,False) else do { o <- try (openFile fnam WriteMode) ; case o of Left e -> return (stderr,False,False) Right h -> return (h,True,True) } ; hwt <- lift $ hIsWritable hnd ; if hop && hwt then return $ Just (hnd,cls) else do { if cls then lift $ hClose hnd else return () ; swishError ("Cannot write file: "++fnam) 3 ; return Nothing } } -------------------------------------------------------------------------------- -- -- Copyright (c) 2003, G. KLYNE. All rights reserved. -- -- This file is part of Swish. -- -- Swish is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- Swish is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with Swish; if not, write to: -- The Free Software Foundation, Inc., -- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -- -------------------------------------------------------------------------------- -- $Source: /file/cvsdev/HaskellRDF/SwishCommands.hs,v $ -- $Author: graham $ -- $Revision: 1.13 $ -- $Log: SwishCommands.hs,v $ -- Revision 1.13 2003/12/11 19:11:07 graham -- Script processor passes all initial tests. -- -- Revision 1.12 2003/12/05 02:31:32 graham -- Script parsing complete. -- Some Swish script functions run successfully. -- Command execution to be completed. -- -- Revision 1.11 2003/12/04 02:53:27 graham -- More changes to LookupMap functions. -- SwishScript logic part complete, type-checks OK. -- -- Revision 1.10 2003/12/01 18:51:38 graham -- Described syntax for Swish script. -- Created Swish scripting test data. -- Edited export/import lists in Swish main program modules. -- -- Revision 1.9 2003/09/24 18:50:53 graham -- Revised module format to be Haddock compatible. -- -- Revision 1.8 2003/06/03 19:24:13 graham -- Updated all source modules to cite GNU Public Licence -- -- Revision 1.7 2003/05/29 12:39:49 graham -- Improved error handling for stand-alone swish program -- -- Revision 1.6 2003/05/29 10:49:08 graham -- Added and tested merge option (-m) for Swish program -- -- Revision 1.5 2003/05/29 00:57:37 graham -- Resolved swish performance problem, which turned out to an inefficient -- method used by the parser to add arcs to a graph. -- -- Revision 1.4 2003/05/28 17:39:30 graham -- Trying to track down N3 formatter performance problem. -- -- Revision 1.3 2003/05/23 00:03:55 graham -- Added HUnit test module for swish program. -- Greatly enhanced N3Formatter tests -- -- Revision 1.2 2003/05/21 13:34:13 graham -- Various N3 parser bug fixes. -- Need to fix handling of :name terms. -- -- Revision 1.1 2003/05/20 23:36:30 graham -- Add new Swish modules --