예제 #1
0
bool Streader_read_dict(Streader* sr, Dict_item_reader ir, void* userdata)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    // Check opening brace
    if (!(Streader_skip_whitespace(sr) && Streader_match_char(sr, '{')))
    {
        Streader_set_error(sr, "Expected a dictionary opening brace");
        return false;
    }

    // Check empty dictionary
    if (Streader_try_match_char(sr, '}'))
        return true;

    if (ir == NULL)
    {
        Streader_set_error(sr, "Expected an empty dictionary");
        return false;
    }

    // Read key/value pairs
    do
    {
        char key[STREADER_DICT_KEY_LENGTH_MAX + 1] = "";
        if (!(Streader_read_string(sr, STREADER_DICT_KEY_LENGTH_MAX + 1, key) &&
                    Streader_match_char(sr, ':') &&
                    ir(sr, key, userdata)))
            return false;
    } while (Streader_try_match_char(sr, ','));

    // Check closing brace
    if (!Streader_match_char(sr, '}'))
    {
        Streader_set_error(sr, "Expected a dictionary closing brace");
        return false;
    }

    return true;
}
예제 #2
0
bool Streader_read_list(Streader* sr, List_item_reader ir, void* userdata)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    // Check opening bracket
    if (!(Streader_skip_whitespace(sr) && Streader_match_char(sr, '[')))
    {
        Streader_set_error(sr, "Expected a list opening bracket");
        return false;
    }

    // Check empty list
    if (Streader_try_match_char(sr, ']'))
        return true;

    if (ir == NULL)
    {
        Streader_set_error(sr, "Expected an empty list");
        return false;
    }

    // Read elements
    int32_t index = 0;
    do
    {
        if (!ir(sr, index, userdata))
            return false;
        ++index;
    } while (Streader_try_match_char(sr, ','));

    // Check closing bracket
    if (!Streader_match_char(sr, ']'))
    {
        Streader_set_error(sr, "Expected a list closing bracket");
        return false;
    }

    return true;
}
예제 #3
0
파일: Tuning_table.c 프로젝트: kagu/kunquat
static bool Streader_read_tuning(Streader* sr, double* cents)
{
    rassert(sr != NULL);
    rassert(cents != NULL);

    if (Streader_is_error_set(sr))
        return false;

    if (Streader_try_match_char(sr, '['))
    {
        int64_t num = 0;
        int64_t den = 0;
        if (!Streader_readf(sr, "%i,%i]", &num, &den))
            return false;

        if (num <= 0)
        {
            Streader_set_error(sr, "Numerator must be positive");
            return false;
        }
        if (den <= 0)
        {
            Streader_set_error(sr, "Denominator must be positive");
            return false;
        }

        *cents = log2((double)num / (double)den) * 1200;
    }
    else
    {
        if (!Streader_read_float(sr, cents))
            return false;

        if (!isfinite(*cents))
        {
            Streader_set_error(sr, "Cents value must be finite");
            return false;
        }
    }

    return true;
}
예제 #4
0
bool Streader_read_float(Streader* sr, double* dest)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    Streader_skip_whitespace(sr);

    // Note: Not completely accurate, but not supposed to be portable anyway...

    bool is_negative = false;
    int64_t significand = 0;
    int significand_shift = 0;
    int significant_digits_read = 0;

    int exponent = 0;
    bool exponent_is_negative = false;

    // Negation
    if (Streader_try_match_char(sr, '-'))
        is_negative = true;

    if (Streader_end_reached(sr))
    {
        Streader_set_error(sr, "No digits found");
        return false;
    }

    // Significand
    if (CUR_CH == '0')
    {
        ++sr->pos;
    }
    else if (strchr(NONZERO_DIGITS, CUR_CH) != NULL)
    {
        while (!Streader_end_reached(sr) && isdigit(CUR_CH))
        {
            if (significant_digits_read < SIGNIFICANT_MAX)
            {
                // Store the digit into our significand
                rassert(significand < INT64_MAX / 10);
                significand *= 10;
                significand += (int64_t)(CUR_CH - '0');
                ++significant_digits_read;
            }
            else
            {
                // We have run out of accuracy, just update magnitude
                ++significand_shift;
            }

            ++sr->pos;
        }
    }
    else
    {
        Streader_set_error(sr, "No digits found");
        return false;
    }

    // Decimal part
    if (!Streader_end_reached(sr) && CUR_CH == '.')
    {
        ++sr->pos;

        while (!Streader_end_reached(sr) && isdigit(CUR_CH))
        {
            if (significant_digits_read < SIGNIFICANT_MAX)
            {
                // Append digit to our significand and compensate in shift
                rassert(significand < INT64_MAX / 10);
                significand *= 10;
                significand += (int64_t)(CUR_CH - '0');
                --significand_shift;

                if (significand != 0)
                    ++significant_digits_read;
            }

            ++sr->pos;
        }

        // Require at least one digit
        if (sr->str[sr->pos - 1] == '.')
        {
            Streader_set_error(sr, "No digits found after decimal point");
            return false;
        }
    }

    // Exponent part
    if (!Streader_end_reached(sr) &&
            ((CUR_CH == 'e') || (CUR_CH == 'E'))
       )
    {
        ++sr->pos;

        if (Streader_end_reached(sr))
        {
            Streader_set_error(sr, "No digits found after exponent indicator");
            return false;
        }

        if (CUR_CH == '+')
        {
            ++sr->pos;
        }
        else if (CUR_CH == '-')
        {
            exponent_is_negative = true;
            ++sr->pos;
        }

        while (!Streader_end_reached(sr) && isdigit(CUR_CH))
        {
            rassert(exponent < INT_MAX / 10);
            exponent *= 10;
            exponent += (int)(CUR_CH - '0');

            ++sr->pos;
        }

        // Require at least one digit
        if (!isdigit(sr->str[sr->pos - 1]))
        {
            Streader_set_error(sr, "No digits found after exponent indicator");
            return false;
        }
    }

    if (!Streader_end_reached(sr) && isalpha(CUR_CH))
    {
        Streader_set_error(sr, "Trailing letters after a number");
        return false;
    }

    // Optimise trailing zeros away from the significand
    if (significand != 0)
    {
        while (significand % 10 == 0)
        {
            significand /= 10;
            ++significand_shift;
        }
    }

    // Convert the number
    if (exponent_is_negative)
        exponent = -exponent;
    int final_shift = significand_shift + exponent;

    double result = (double)significand;

    double abs_magnitude = pow(10, abs(final_shift));
    if (final_shift >= 0)
        result *= abs_magnitude;
    else
        result /= abs_magnitude;

    if (is_negative)
        result = -result;

    if (dest != NULL)
        *dest = result;

    return true;
}
예제 #5
0
bool Streader_read_int(Streader* sr, int64_t* dest)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    Streader_skip_whitespace(sr);

    int64_t result = 0;
    const bool negative = Streader_try_match_char(sr, '-');

    if (Streader_end_reached(sr))
    {
        Streader_set_error(sr, "Unexpected end of data");
        return false;
    }

    if (CUR_CH == '0')
    {
        ++sr->pos;
        if (!Streader_end_reached(sr) && isalnum(CUR_CH))
        {
            Streader_set_error(sr, "Unexpected characters after initial zero");
            return false;
        }
    }
    else if (strchr(NONZERO_DIGITS, CUR_CH) != NULL)
    {
        if (negative)
        {
            static const int64_t safe_lower = INT64_MIN / 10;

            while (!Streader_end_reached(sr) && isdigit(CUR_CH))
            {
                // Check for multiplication overflow
                if (result < safe_lower)
                {
                    Streader_set_error(sr, "Integer is too small");
                    return false;
                }
                result *= 10;

                const int64_t contrib = CUR_CH - '0';

                // Check for addition overflow
                if (INT64_MIN + contrib > result)
                {
                    Streader_set_error(sr, "Integer is too small");
                    return false;
                }
                result -= contrib;

                ++sr->pos;
            }
        }
        else
        {
            static const int64_t safe_upper = INT64_MAX / 10;

            while (!Streader_end_reached(sr) && isdigit(CUR_CH))
            {
                // Check for multiplication overflow
                if (result > safe_upper)
                {
                    Streader_set_error(sr, "Integer is too large");
                    return false;
                }
                result *= 10;

                const int64_t contrib = CUR_CH - '0';

                // Check for addition overflow
                if (INT64_MAX - contrib < result)
                {
                    Streader_set_error(sr, "Integer is too large");
                    return false;
                }
                result += contrib;

                ++sr->pos;
            }
        }
    }
    else
    {
        Streader_set_error(sr, "No digits found");
        return false;
    }

    if (dest != NULL)
        *dest = result;

    return true;
}