root/src/kits/debugger/value/value_formatters/IntegerValueFormatter.cpp
/*
 * Copyright 2015, Rene Gollent, rene@gollent.com.
 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Distributed under the terms of the MIT License.
 */
#include "IntegerValueFormatter.h"

#include <new>

#include <ctype.h>

#include "IntegerFormatter.h"
#include "IntegerValue.h"


// #pragma mark - IntegerValueFormatter


IntegerValueFormatter::IntegerValueFormatter(Config* config)
        :
        ValueFormatter(),
        fConfig(config)
{
        if (fConfig != NULL)
                fConfig->AcquireReference();
}


IntegerValueFormatter::~IntegerValueFormatter()
{
        if (fConfig != NULL)
                fConfig->ReleaseReference();
}


Settings*
IntegerValueFormatter::GetSettings() const
{
        return fConfig != NULL ? fConfig->GetSettings() : NULL;
}


status_t
IntegerValueFormatter::FormatValue(Value* _value, BString& _output)
{
        IntegerValue* value = dynamic_cast<IntegerValue*>(_value);
        if (value == NULL)
                return B_BAD_VALUE;

        // format the value
        integer_format format = fConfig != NULL
                ? fConfig->IntegerFormat() : INTEGER_FORMAT_DEFAULT;
        char buffer[32];
        if (!IntegerFormatter::FormatValue(value->GetValue(), format,  buffer,
                        sizeof(buffer))) {
                return B_BAD_VALUE;
        }

        _output.SetTo(buffer);

        return B_OK;
}


bool
IntegerValueFormatter::SupportsValidation() const
{
        return true;
}


bool
IntegerValueFormatter::ValidateFormattedValue(const BString& input,
        type_code type) const
{
        ::Value* value = NULL;
        return _PerformValidation(input, type, value, false) == B_OK;
}


status_t
IntegerValueFormatter::GetValueFromFormattedInput(const BString& input,
        type_code type, Value*& _output) const
{
        return _PerformValidation(input, type, _output, true);
}


status_t
IntegerValueFormatter::_PerformValidation(const BString& input, type_code type,
        ::Value*& _output, bool wantsValue) const
{
        integer_format format;
        if (fConfig != NULL)
                format = fConfig->IntegerFormat();
        else {
                bool isSigned;
                if (BVariant::TypeIsInteger(type, &isSigned)) {
                        format = isSigned ? INTEGER_FORMAT_SIGNED
                                : INTEGER_FORMAT_UNSIGNED;
                } else
                        return B_BAD_VALUE;
        }

        status_t error = B_OK;
        if (format == INTEGER_FORMAT_UNSIGNED
                || format >= INTEGER_FORMAT_HEX_DEFAULT) {
                error = _ValidateUnsigned(input, type, _output, format, wantsValue);
        } else
                error = _ValidateSigned(input, type, _output, wantsValue);

        return error;
}


status_t
IntegerValueFormatter::_ValidateSigned(const BString& input, type_code type,
        ::Value*& _output, bool wantsValue) const
{
        const char* text = input.String();
        char *parseEnd = NULL;
        intmax_t parsedValue = strtoimax(text, &parseEnd, 10);
        if (parseEnd - text < input.Length() && !isspace(*parseEnd))
                return B_NO_MEMORY;

        BVariant newValue;
        switch (type) {
                case B_INT8_TYPE:
                {
                        if (parsedValue < INT8_MIN || parsedValue > INT8_MAX)
                                return B_BAD_VALUE;

                        newValue.SetTo((int8)parsedValue);
                        break;
                }
                case B_INT16_TYPE:
                {
                        if (parsedValue < INT16_MIN || parsedValue > INT16_MAX)
                                return B_BAD_VALUE;

                        newValue.SetTo((int16)parsedValue);
                        break;
                }
                case B_INT32_TYPE:
                {
                        if (parsedValue < INT32_MIN || parsedValue > INT32_MAX)
                                return B_BAD_VALUE;

                        newValue.SetTo((int32)parsedValue);
                        break;
                }
                case B_INT64_TYPE:
                {
                        newValue.SetTo((int64)parsedValue);
                        break;
                }
                default:
                        return B_BAD_VALUE;
        }

        if (wantsValue) {
                _output = new(std::nothrow) IntegerValue(newValue);
                if (_output == NULL)
                        return B_NO_MEMORY;
        }

        return B_OK;
}


status_t
IntegerValueFormatter::_ValidateUnsigned(const BString& input, type_code type,
        ::Value*& _output, integer_format format, bool wantsValue) const
{
        const char* text = input.String();
        int32 base = format == INTEGER_FORMAT_UNSIGNED ? 10 : 16;

        char *parseEnd = NULL;
        uintmax_t parsedValue = strtoumax(text, &parseEnd, base);
        if (parseEnd - text < input.Length() && !isspace(*parseEnd))
                return B_BAD_VALUE;

        BVariant newValue;
        switch (type) {
                case B_UINT8_TYPE:
                {
                        if (parsedValue > UINT8_MAX)
                                return B_BAD_VALUE;

                        newValue.SetTo((uint8)parsedValue);
                        break;
                }
                case B_UINT16_TYPE:
                {
                        if (parsedValue > UINT16_MAX)
                                return B_BAD_VALUE;

                        newValue.SetTo((uint16)parsedValue);
                        break;
                }
                case B_UINT32_TYPE:
                {
                        if (parsedValue > UINT32_MAX)
                                return B_BAD_VALUE;

                        newValue.SetTo((uint32)parsedValue);
                        break;
                }
                case B_UINT64_TYPE:
                {
                        newValue.SetTo((uint64)parsedValue);
                        break;
                }
                default:
                        return B_BAD_VALUE;
        }

        if (wantsValue) {
                _output = new(std::nothrow) IntegerValue(newValue);
                if (_output == NULL)
                        return B_NO_MEMORY;
        }

        return B_OK;
}



// #pragma mark - Config


IntegerValueFormatter::Config::~Config()
{
}