# 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

File | common/interface/command.h
Public functions | CreateCommandProvider
Classes | ICommandProvider ICommand
Examples | Command

# 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;
        }
    }