aboutsummaryrefslogtreecommitdiff
path: root/src/function/external_command.cc
diff options
context:
space:
mode:
authorAdrian Kummerlaender2014-08-16 23:30:36 +0200
committerAdrian Kummerlaender2014-08-16 23:30:36 +0200
commitf6ff54c492df81018cf48da039ee681508f88e46 (patch)
tree0659e0f5bf4529b8c83bebc87119607638f98b7f /src/function/external_command.cc
parent7f6611cded8c1591f1aa1a4c7d70505cb21e7967 (diff)
downloadInputXSLT-f6ff54c492df81018cf48da039ee681508f88e46.tar
InputXSLT-f6ff54c492df81018cf48da039ee681508f88e46.tar.gz
InputXSLT-f6ff54c492df81018cf48da039ee681508f88e46.tar.bz2
InputXSLT-f6ff54c492df81018cf48da039ee681508f88e46.tar.lz
InputXSLT-f6ff54c492df81018cf48da039ee681508f88e46.tar.xz
InputXSLT-f6ff54c492df81018cf48da039ee681508f88e46.tar.zst
InputXSLT-f6ff54c492df81018cf48da039ee681508f88e46.zip
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<std::string>" 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
Diffstat (limited to 'src/function/external_command.cc')
-rw-r--r--src/function/external_command.cc99
1 files changed, 99 insertions, 0 deletions
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 <xalanc/XSLT/XSLTInputSource.hpp>
+
+#include <xercesc/parsers/XercesDOMParser.hpp>
+
+#include <boost/process.hpp>
+
+#include <sstream>
+
+#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(
+ "<output>" + std::string(
+ (std::istreambuf_iterator<char>(outputStream)),
+ (std::istreambuf_iterator<char>())
+ ) + "</output>"
+ );
+
+ 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<std::string> 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<char>(exception.msg)
+ );
+ }
+ } else {
+ result.setAttribute("result", "error");
+ }
+
+
+ return domDocument;
+}
+
+}