From f6ff54c492df81018cf48da039ee681508f88e46 Mon Sep 17 00:00:00 2001 From: Adrian Kummerlaender Date: Sat, 16 Aug 2014 23:30:36 +0200 Subject: Implemented primitive optional parameter support for external functions * renamed FunctionExternalTextFormatter into FunctionExternalCommand ** the goal is to provide a general interface to a variety of external commands *** e.g. not just text formatters but system utilities for file management and so on ** this requires the stdin parameter to be optional as not all external commands require stdin input * implemented "filter_derived" helper template to determine amount of optional parameters ** optional parameters are defined as "boost::optional" specializations *** they in turn can be detected by checking if "boost::optional_detail::optional_tag" is a base class * "callConstructDocument" member method of "FunctionBase" performs additional bounds checking of parameter vector * "boost::optional" specific member overload was added to "XObjectValue" helper class ** we will have to provide full specializations for all optional types as C++ prohibits partial member function template specialization * renamed the external function in "PlattformGuard" * changed README.md and test cases accordingly --- src/function/external_command.cc | 99 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/function/external_command.cc (limited to 'src/function/external_command.cc') diff --git a/src/function/external_command.cc b/src/function/external_command.cc new file mode 100644 index 0000000..bd2bf84 --- /dev/null +++ b/src/function/external_command.cc @@ -0,0 +1,99 @@ +#include "external_command.h" + +#include + +#include + +#include + +#include + +#include "support/xerces_string_guard.h" +#include "support/dom/result_node_facade.h" + +namespace { + +using InputXSLT::XercesStringGuard; + +inline xercesc::DOMNode* importDocumentElement( + boost::process::pistream& outputStream, + xercesc::DOMDocument* const domDocument +) { + std::stringstream xmlStream( + "" + std::string( + (std::istreambuf_iterator(outputStream)), + (std::istreambuf_iterator()) + ) + "" + ); + + xercesc::XercesDOMParser parser; + parser.parse(xalan::XSLTInputSource(xmlStream)); + + return domDocument->importNode( + parser.getDocument()->getDocumentElement(), + true + ); +} + +} + +namespace InputXSLT { + +DomDocumentCache::document_ptr FunctionExternalCommand::constructDocument( + std::string command, + boost::optional stdinText +) const { + DomDocumentCache::document_ptr domDocument( + DomDocumentCache::createDocument("content") + ); + + boost::process::context context; + context.environment = boost::process::self::get_environment(); + context.stdout_behavior = boost::process::capture_stream(); + context.stdin_behavior = boost::process::capture_stream(); + + boost::process::child commandProcess( + boost::process::launch_shell(command, context) + ); + + if ( stdinText ) { + boost::process::postream& inputStream = commandProcess.get_stdin(); + inputStream << *stdinText; + inputStream.close(); + } + + boost::process::pistream& outputStream = commandProcess.get_stdout(); + boost::process::status status = commandProcess.wait(); + + ResultNodeFacade result(domDocument.get(), "output"); + result.setAttribute("command", command); + result.setAttribute("code", std::to_string(status.exit_status())); + + if ( status.exited() ) { + try { + result.setContent( + importDocumentElement( + outputStream, + domDocument.get() + )->getChildNodes() + ); + + result.setAttribute("result", "success"); + } + catch ( const xercesc::DOMException& exception ) { + result.setAttribute("result", "error"); + + result.setValueNode( + "error", + *XercesStringGuard(exception.msg) + ); + } + } else { + result.setAttribute("result", "error"); + } + + + return domDocument; +} + +} -- cgit v1.2.3