Commands
    
        Interface for asyncronously operating on commands. You can write to STDIN, read from STDOUT and STDERR.
	
    
        Note: currently the implementation is done in a separate thread for each new command, 
        as there is no possibility to read or write asynchronously from file descriptors.
    
    
    File information
    
    
    
    Functions
    Functions to initialize
    
    class ICommandProvider * CreateCommandProvider(class IIoMux * iomux);
    Overview
    This function will create an ICommandProvider instance. This instance can be used to create ICommand objects.
    
    CreateCommandProvider
    - 
            
Parameters
            
                | class IIoMux * iomux | The iomux instance which is to be used. | 
            
        Return value
        The ICommandProvider instance. That instance can be freed as soon as it no longer is used by calling the C++ delete operator.
     
	
    
    Classes
	ICommandProvider
    class ICommandProvider {
public:
    virtual class ICommand * CreateCommand(class IInstanceLog * const log, class UTask * user, const char * command, int expectedExitCode, size_t initialReadLength = 0) = 0;
};
    Public functions
    virtual class ICommand * CreateCommand
    
        Creates an ICommand instance.
        Parameters
        
            | class IInstanceLog * const log | The IInstanceLog instance which is to be used. | 
            | class UTask * user | The UTask instance which will receive TaskProgress/TaskComplete/TaskFailed callbacks. | 
            | const char * command | The actual command which will be executed. | 
            | int expectedExitCode | The expected exit code. Use a negative value to ignore the exit code. | 
            | size_t initialReadLength | You can specify a number to directly start reading the command output. | 
        
        
        Return value
        The ICommand instance. That instance can be freed as soon as it called TaskFailed/TaskComplete, not before!
    
    
    Classes
	ICommand
    
        ICommand is derived from ITask, so the ITask/UTask mechanisms are used for progress and completion.
        The ITask::Start function is called inside CreateCommand, so it is not needed to call this function on your own.
    
    
        The buffer of the read data is maintained within this class.
        STDERR is automatically redirected and can be fetched afterwards with Error(). Note that max 8192 bytes are fetched from STDERR, the remaining data is discarded.
        
General handling
        The TaskProgress progress parameter is used differently, depending on a previous Read or Write. Valid values are:
        
            - COMMAND_PROGRESS_READ
 
            - COMMAND_PROGRESS_WRITE
 
        
        
            - The TaskComplete callback is triggered when the process has terminated and all data has been read or after ICommand::Close() has been called.
 
            - The TaskFailed callback is triggered when something failed. In this case the command has already terminated.
 
            - The TaskProgress(this, COMMAND_PROGRESS_READ) callback is triggered after a previous Read(...) call when the data is available. You can retrieve the data with Get() afterwards.
 
            - The TaskProgress(this, COMMAND_PROGRESS_WRITE) callback is triggered after a previous Write(...) call when the data has been written.
 
        
    
    class ICommand : public ITask {
public:
    virtual void Write(byte * data, size_t length, bool last = false) = 0;
    virtual void Read(size_t length) = 0;
    virtual void Get(const byte * & data, size_t & length) = 0;
    virtual void Close() = 0;
    virtual const char * Error() = 0;
    virtual int GetExitCode() = 0;
};
    
    Public functions
    void Write
    
        Initiates writing of data to STDIN. May be called after TaskProgress from the previous block.
        You mustn't call several writes without waiting for the TaskProgress callback which indicates that the data has been written.
        Parameters
        
            | byte * data | A pointer to a byte array. | 
            | size_t length | The length of the data to write. | 
            | bool last | Set true if this is the last write call, which closes STDIN. | 
        
    
    void Read
    
        Initiates reading of the next block. May be called after TaskProgress from the previous block.
        You mustn't call several reads without waiting for the TaskProgress callback which indicates that the data has been read.
        Parameters
        
            | size_t length | The length of the data to read. | 
        
    
    void Get
    
        Gets a pointer to the read block of data. May be called after the TaskProgress for the read operation. 
        The pointer is valid until the next call to Read. I the length is not equal to the length of a previous Read call, the end of the stream is reached and you'll get a TaskComplete/TaskFailed afterwards.
        Parameters
        
            | const byte * & data | Pointer reference to the data buffer. | 
            | size_t & length | The available size in the data buffer. | 
        
    
    void Close
    
        Terminates the process if it is still running. You do not need to call Close() if you do not want to kill the process before it ends on its own.
        Parameters
        
    
    const char * Error
    
        Returns the output of STDERR or NULL if nothing has been written to STDERR.
        Parameters
        
        Return value
        The const char * error string.
    
    int GetExitCode()
    
        Parameters
        
        Return value
        The int exit code of the command.
    
    
    Examples
	Command
    
// in main.cpp
class ICommandProvider * provider = CreateCommandProvider(iomux);
    
// another cpp file
class Test : public UTask {
    class ICommand * command;
public:
    Test(class ICommandProvider * provider, class IInstanceLog * log) {
        this->command = provider::CreateCommand(log, this, "/usr/bin/...", 0);
        byte * data = ...;
        this->command->Write(data, dataLen, true);  // we write one data buffer and wait for TaskProgress
    }
    
    void TaskProgress(class ITask * task, dword progress = 0) {
        if(progress == COMMAND_PROGRESS_WRITE) {    // just one write op, so read now
            this->command->Read(1000);              // read 1000 bytes    
        }
        else if(progress == COMMAND_PROGRESS_READ) {
            size_t length = 0;
            const byte * data = NULL;
            this->command->Get(data, length);
            // do something with the data
            if(length == 1000) {                    // more data available
                this->command->Read(1000);
            }
            // else wait for TaskComplete/Failed
        }
    }
    
    void TaskComplete(class ITask * task) {
        delete this->command;   // this->command == task
        this->command = nullptr;
    }
    
    void TaskFailed(class ITask * task) {
        debug->printf("%i %s", this->command->GetExitCode(), this->command->Error());
        delete this->command;   // this->command == task
        this->command = nullptr;
    }
}