From 1936499250425a1d50d70759758c7385b4bdf6d4 Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 24 Feb 2009 10:40:18 -0500 Subject: [PATCH] ENH: Create cmProcessTools to parse child output This class provides a RunProcess method to run a child process and send its output to an abstract parsing interface. This also provides a simple line parser and logger implementing the parsing interface. --- Source/CMakeLists.txt | 2 + Source/cmProcessTools.cxx | 93 +++++++++++++++++++++++++++++++++++++++ Source/cmProcessTools.h | 82 ++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 Source/cmProcessTools.cxx create mode 100644 Source/cmProcessTools.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 318033941..964099c76 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -187,6 +187,8 @@ SET(SRCS cmOrderDirectories.h cmPolicies.h cmPolicies.cxx + cmProcessTools.cxx + cmProcessTools.h cmProperty.cxx cmProperty.h cmPropertyDefinition.cxx diff --git a/Source/cmProcessTools.cxx b/Source/cmProcessTools.cxx new file mode 100644 index 000000000..ef40f5757 --- /dev/null +++ b/Source/cmProcessTools.cxx @@ -0,0 +1,93 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#include "cmProcessTools.h" + +#include + +//---------------------------------------------------------------------------- +void cmProcessTools::RunProcess(struct cmsysProcess_s* cp, + OutputParser* out, OutputParser* err) +{ + cmsysProcess_Execute(cp); + char* data = 0; + int length = 0; + int p; + while((out||err) && (p=cmsysProcess_WaitForData(cp, &data, &length, 0), p)) + { + if(out && p == cmsysProcess_Pipe_STDOUT) + { + if(!out->Process(data, length)) + { + out = 0; + } + } + else if(err && p == cmsysProcess_Pipe_STDERR) + { + if(!err->Process(data, length)) + { + err = 0; + } + } + } + cmsysProcess_WaitForExit(cp, 0); +} + + +//---------------------------------------------------------------------------- +cmProcessTools::LineParser::LineParser(char sep, bool ignoreCR): + Separator(sep), IgnoreCR(ignoreCR), Log(0), Prefix(0) +{ +} + +//---------------------------------------------------------------------------- +void cmProcessTools::LineParser::SetLog(std::ostream* log, const char* prefix) +{ + this->Log = log; + this->Prefix = prefix? prefix : ""; +} + +//---------------------------------------------------------------------------- +bool cmProcessTools::LineParser::ProcessChunk(const char* first, int length) +{ + const char* last = first + length; + for(const char* c = first; c != last; ++c) + { + if(*c == this->Separator) + { + // Log this line. + if(this->Log && this->Prefix) + { + *this->Log << this->Prefix << this->Line << "\n"; + } + + // Hand this line to the subclass implementation. + if(!this->ProcessLine()) + { + this->Line = ""; + return false; + } + + this->Line = ""; + } + else if(*c != '\r' || !this->IgnoreCR) + { + // Append this character to the line under construction. + this->Line.append(1, *c); + } + } + return true; +} diff --git a/Source/cmProcessTools.h b/Source/cmProcessTools.h new file mode 100644 index 000000000..c438527da --- /dev/null +++ b/Source/cmProcessTools.h @@ -0,0 +1,82 @@ +/*========================================================================= + + Program: CMake - Cross-Platform Makefile Generator + Module: $RCSfile$ + Language: C++ + Date: $Date$ + Version: $Revision$ + + Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. + See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details. + + This software is distributed WITHOUT ANY WARRANTY; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the above copyright notices for more information. + +=========================================================================*/ +#ifndef cmProcessTools_h +#define cmProcessTools_h + +#include "cmStandardIncludes.h" + +/** \class cmProcessTools + * \brief Helper classes for process output parsing + * + */ +class cmProcessTools +{ +public: + /** Abstract interface for process output parsers. */ + class OutputParser + { + public: + /** Process the given output data from a tool. Processing may be + done incrementally. Returns true if the parser is interested + in any more data and false if it is done. */ + bool Process(const char* data, int length) + { return this->ProcessChunk(data, length); } + protected: + /** Implement in a subclass to process a chunk of data. It should + return true only if it is interested in more data. */ + virtual bool ProcessChunk(const char* data, int length) = 0; + }; + + /** Process output parser that extracts one line at a time. */ + class LineParser: public OutputParser + { + public: + /** Construct with line separation character and choose whether to + ignore carriage returns. */ + LineParser(char sep = '\n', bool ignoreCR = true); + + /** Configure logging of lines as they are extracted. */ + void SetLog(std::ostream* log, const char* prefix); + protected: + char Separator; + bool IgnoreCR; + std::ostream* Log; + const char* Prefix; + std::string Line; + virtual bool ProcessChunk(const char* data, int length); + + /** Implement in a subclass to process one line of input. It + should return true only if it is interested in more data. */ + virtual bool ProcessLine() = 0; + }; + + /** Trivial line handler for simple logging. */ + class OutputLogger: public LineParser + { + public: + OutputLogger(std::ostream& log, const char* prefix = 0) + { this->SetLog(&log, prefix); } + private: + virtual bool ProcessLine() { return true; } + }; + + /** Run a process and send output to given parsers. */ + static void RunProcess(struct cmsysProcess_s* cp, + OutputParser* out, OutputParser* err = 0); +}; + +#endif