/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
#ifndef cmProcessTools_h
#define cmProcessTools_h

#include "cmConfigure.h"  // IWYU pragma: keep
#include "cmProcessOutput.h"

#include <iosfwd>
#include <string.h>
#include <string>

/** \class cmProcessTools
 * \brief Helper classes for process output parsing
 *
 */
class cmProcessTools
{
public:
    typedef cmProcessOutput::Encoding Encoding;
    /** 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);
        }
        bool Process(const char* data)
        {
            return this->Process(data, static_cast<int>(strlen(data)));
        }

        virtual ~OutputParser() {}

    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:
        std::ostream* Log;
        const char*   Prefix;
        std::string   Line;
        char          Separator;
        char          LineEnd;
        bool          IgnoreCR;
        bool          ProcessChunk(const char* data, int length) override;

        /** 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 = nullptr)
        {
            this->SetLog(&log, prefix);
        }

    private:
        bool ProcessLine() override { return true; }
    };

    /** Run a process and send output to given parsers.  */
    static void RunProcess(struct cmsysProcess_s* cp, OutputParser* out,
                           OutputParser* err      = nullptr,
                           Encoding      encoding = cmProcessOutput::Auto);
};

#endif
