Program Listing for File CommandLine.h

Program Listing for File CommandLine.h#

Return to documentation for file (src/cli/CommandLine.h)

#pragma once

/* toolchain */
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <string>

/* internal */
#include "../logging/PrintfLogger.h"
#include "../result.h"

namespace Coral
{

template <typename element_t = char, class T = PrintfLogger>
class ElementCommandLine : public HasLogInterface<T>
{
  public:
    using String = std::basic_string<element_t>;

    ElementCommandLine(const element_t **_line, std::size_t _length,
                       LogInterface<T> *_log = nullptr)
        : HasLogInterface<T>(_log), line(_line), command(_line[0]),
          length(_length)
    {
        /* At minimum a command must be provided. */
        assert(length);

        /* All arguments follow the command. */
        line = &line[1];
        length--;
    }

    template <std::size_t index>
    Result as_long(long &output, LogInterface<T> *_log = nullptr)
    {
        bool result = false;
        auto elem = at<index>(_log);

        if (elem)
        {
            char *endptr;
            output = std::strtol(elem, &endptr, 0);

            /* Conversion succeeded if we reached the end of the string. */
            result = *endptr == '\0';

            if (not result)
            {
                this->log(_log,
                          "(index %zu) Couldn't convert '%s' to an integer "
                          "(error at "
                          "'%s').\n",
                          index, elem, endptr);
            }
        }

        return ToResult(result);
    }

    template <std::size_t index>
    Result as_double(double &output, LogInterface<T> *_log = nullptr)
    {
        bool result = false;
        auto elem = at<index>(_log);

        if (elem)
        {
            char *endptr;
            output = std::strtod(elem, &endptr);

            /* Conversion succeeded if we reached the end of the string. */
            result = *endptr == '\0';

            if (not result)
            {
                this->log(
                    _log,
                    "(index %zu) Couldn't convert '%s' to a double (error at "
                    "'%s').\n",
                    index, elem, endptr);
            }
        }

        return ToResult(result);
    }

    template <std::size_t index>
    Result as_bool(bool &output, LogInterface<T> *_log = nullptr)
    {
        bool result = false;
        auto elem = at<index>(_log);

        if (elem)
        {
            String value(elem);
            if (value.compare("true") == 0)
            {
                output = true;
                result = true;
            }
            else if (value.compare("false") == 0)
            {
                output = false;
                result = true;
            }
            else
            {
                this->log(_log,
                          "(index %zu) Got '%s' and not literal value 'true' "
                          "or 'false'.\n",
                          index, elem);
            }
        }

        return ToResult(result);
    }

    template <std::size_t index>
    const element_t *at(LogInterface<T> *_log = nullptr)
    {
        const element_t *result = nullptr;

        if (length > index)
        {
            result = line[index];
        }
        else
        {
            this->log(
                _log,
                "(index %zu) No element at index %zu (%zu arguments total).\n",
                index, index, length);
        }

        return result;
    }

    inline const String get_command()
    {
        return String(command);
    }

  protected:
    const element_t **line;
    const element_t *command;
    std::size_t length;
};

using CommandLine = ElementCommandLine<>;

} // namespace Coral