예제 #1
0
bool Streader_read_tstamp(Streader* sr, Tstamp* dest)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    int64_t beats = 0;
    int64_t rem = 0;

    if (!(Streader_match_char(sr, '[')  &&
                Streader_read_int(sr, &beats) &&
                Streader_match_char(sr, ',')  &&
                Streader_read_int(sr, &rem)   &&
                Streader_match_char(sr, ']')))
    {
        Streader_set_error(sr, "Expected a valid timestamp");
        return false;
    }

    if (rem < 0 || rem >= KQT_TSTAMP_BEAT)
    {
        Streader_set_error(
                sr,
                "Timestamp remainder %" PRId64 " out of range [0..%ld)",
                rem,
                KQT_TSTAMP_BEAT);
        return false;
    }

    if (dest != NULL)
        Tstamp_set(dest, beats, (int32_t)rem);

    return true;
}
예제 #2
0
bool Streader_read_piref(Streader* sr, Pat_inst_ref* dest)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return false;

    int64_t pat = 0;
    int64_t inst = 0;

    if (!(Streader_match_char(sr, '[') &&
                Streader_read_int(sr, &pat)  &&
                Streader_match_char(sr, ',') &&
                Streader_read_int(sr, &inst) &&
                Streader_match_char(sr, ']')))
    {
        Streader_set_error(sr, "Expected a valid pattern instance");
        return false;
    }

    if (pat < 0 || pat >= KQT_PATTERNS_MAX)
    {
        Streader_set_error(
                sr,
                "Pattern number %" PRId64 " out of range [0..%ld)"
                    " in pattern instance",
                pat,
                KQT_PATTERNS_MAX);
        return false;
    }

    if (inst < 0 || inst >= KQT_PAT_INSTANCES_MAX)
    {
        Streader_set_error(
                sr,
                "Pattern instance number %" PRId64 " out of range [0..%ld)"
                    " in pattern instance",
                inst,
                KQT_PAT_INSTANCES_MAX);
        return false;
    }

    if (dest != NULL)
    {
        dest->pat = (int16_t)pat;
        dest->inst = (int16_t)inst;
    }

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

    if (Streader_is_error_set(sr))
        return false;

    int64_t seed = 0;

    if (Streader_has_data(sr))
    {
        if (!Streader_read_int(sr, &seed))
            return false;

        if (seed < 0)
        {
            Streader_set_error(sr, "Random seed must be non-negative");
            return false;
        }
    }

    module->random_seed = (uint64_t)seed;

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

    if (Streader_is_error_set(sr))
        return false;

    Streader_skip_whitespace(sr);
    const int64_t start_pos = sr->pos;

    Value* value = VALUE_AUTO;

    if (Streader_read_bool(sr, &value->value.bool_type))
        value->type = VALUE_TYPE_BOOL;
    else if ((recover(sr, start_pos), Streader_read_int(sr, &value->value.int_type)) &&
            (CUR_CH != '.') && (CUR_CH != 'e') && (CUR_CH != 'E'))
        value->type = VALUE_TYPE_INT;
    else if (recover(sr, start_pos),
            (Streader_read_float(sr, &value->value.float_type) &&
             isfinite(value->value.float_type)))
        value->type = VALUE_TYPE_FLOAT;
    else if (recover(sr, start_pos), Streader_read_tstamp(sr, &value->value.Tstamp_type))
        value->type = VALUE_TYPE_TSTAMP;

    if (value->type == VALUE_TYPE_NONE)
        return false;

    if (dest != NULL)
        Value_copy(dest, value);

    return true;
}
예제 #5
0
파일: streader.c 프로젝트: kagu/kunquat
END_TEST


START_TEST(Read_nonzero_int)
{
    char data[128] = "";

    static const int64_t nums[] = { 1, 19, INT64_MAX, -1, -19, INT64_MIN };

    for (size_t i = 0; i < arr_size(nums); ++i)
    {
        sprintf(data, "%" PRId64 " x", nums[i]);
        Streader* sr = init_with_cstr(data);
        int64_t num = 0;
        fail_if(!Streader_read_int(sr, &num),
                "Could not read %" PRId64,
                nums[i]);
        fail_if(num != nums[i],
                "Streader stored %" PRId64 " instead of %" PRId64,
                num, nums[i]);
        fail_if(!Streader_match_char(sr, 'x'),
                "Streader did not consume %" PRId64 " correctly",
                nums[i]);
    }
}
예제 #6
0
파일: streader.c 프로젝트: kagu/kunquat
END_TEST


static bool fill_array_index(Streader* sr, const char* key, void* userdata)
{
    fail_if(sr == NULL, "Callback did not get a Streader");
    fail_if(Streader_is_error_set(sr),
            "Callback was called with Streader error set: %s",
            Streader_get_error_desc(sr));
    fail_if(key == NULL,
            "Callback did not get a key");
    fail_if(strlen(key) != 1 || strchr("0123", key[0]) == NULL,
            "Callback got an unexpected key `%s`",
            key);
    fail_if(userdata == NULL, "Callback did not get userdata");

    int arr_index = key[0] - '0';
    assert(arr_index >= 0);
    assert(arr_index < 4);
    int* array = userdata;

    int64_t num = 0;
    fail_if(!Streader_read_int(sr, &num),
            "Could not read integer from dictionary: %s",
            Streader_get_error_desc(sr));
    fail_if(num != arr_index + 10,
            "Unexpected value %" PRId64 " (expected %d)",
            num, arr_index + 10);

    array[arr_index] = (int)num;

    return true;
}
예제 #7
0
파일: streader.c 프로젝트: kagu/kunquat
END_TEST


#define item_count 4

static bool inc_doubled_int(Streader* sr, int32_t index, void* userdata)
{
    fail_if(sr == NULL, "Callback did not get a Streader");
    fail_if(Streader_is_error_set(sr),
            "Callback was called with Streader error set: %s",
            Streader_get_error_desc(sr));
    fail_if(index < 0,
            "Callback got a negative item index (%" PRId32 ")",
            index);
    fail_if(index >= item_count,
            "Callback got too large an index (%" PRId32 ")",
            index);
    fail_if(userdata == NULL, "Callback did not get userdata");

    int64_t num = 0;
    fail_if(!Streader_read_int(sr, &num),
            "Could not read integer from list index %" PRId32 ": %s",
            index, Streader_get_error_desc(sr));
    fail_if(num != index * 2,
            "Unexpected list item %" PRId64 " (expected %" PRId32 ")",
            num, index * 2);

    int* nums = userdata;
    nums[index] = (int)num + 1;

    return true;
}
예제 #8
0
파일: streader.c 프로젝트: kagu/kunquat
END_TEST


START_TEST(Read_zero_int)
{
    Streader* sr = init_with_cstr("0 x");
    int64_t num = -1;
    fail_if(!Streader_read_int(sr, &num), "Could not read 0");
    fail_if(num != 0, "Streader stored %" PRId64 " instead of 0", num);
    fail_if(!Streader_match_char(sr, 'x'),
            "Streader did not consume 0 correctly");

    sr = init_with_cstr("-0 x");
    num = 1;
    fail_if(!Streader_read_int(sr, &num), "Could not read -0");
    fail_if(num != 0, "Streader stored %" PRId64 " instead of 0", num);
    fail_if(!Streader_match_char(sr, 'x'),
            "Streader did not consume -0 correctly");
}
예제 #9
0
파일: streader.c 프로젝트: kagu/kunquat
static bool readf_dict(Streader* sr, const char* key, void* userdata)
{
    if (userdata == NULL)
        return false;

    if (strcmp(key, "ten") != 0)
        return false;

    int* dest = userdata;
    int64_t result = 0;

    if (!Streader_read_int(sr, &result))
        return false;

    *dest = (int)result;

    return true;
}
예제 #10
0
파일: streader.c 프로젝트: kagu/kunquat
END_TEST


static bool fail_at_index_2(Streader* sr, int32_t index, void* userdata)
{
    (void)sr;
    (void)userdata;

    fail_if(index > 2, "List processing continued after failure");

    if (index == 2)
        return false;

    fail_if(!Streader_read_int(sr, NULL),
            "Could not read an integer from list: %s",
            Streader_get_error_desc(sr));

    return true;
}
예제 #11
0
파일: streader.c 프로젝트: kagu/kunquat
END_TEST


START_TEST(Reading_too_large_int_in_magnitude_fails)
{
    char data[4][128] = { "" };
    sprintf(data[0], "%" PRId64, INT64_MAX);
    sprintf(data[1], "%" PRId64, INT64_MIN);
    sprintf(data[2], "%" PRId64, INT64_MAX);
    sprintf(data[3], "%" PRId64, INT64_MIN);

    // Make sure the overflowing code below makes sense
    for (int i = 0; i < 4; ++i)
    {
        size_t len = strlen(data[i]);
        assert(len > 2);

        assert(isdigit(data[i][len - 1]));
        assert(data[i][len - 1] != '9');
        assert(isdigit(data[i][len - 2]));
        assert(data[i][len - 2] != '9');
        (void)len;
    }

    // Overflow data[0] and data[1] by 1
    ++data[0][strlen(data[0]) - 1];
    ++data[1][strlen(data[1]) - 1];

    // Overflow data[2] and data[3] by 10
    ++data[2][strlen(data[2]) - 2];
    ++data[3][strlen(data[3]) - 2];

    // Test reading
    for (int i = 0; i < 4; ++i)
    {
        Streader* sr = init_with_cstr(data[i]);
        int64_t num = 0;
        fail_if(Streader_read_int(sr, &num),
                "Reading overflowing integer %s succeeded",
                data[i]);
    }
}
예제 #12
0
파일: streader.c 프로젝트: kagu/kunquat
END_TEST


static bool readf_list(Streader* sr, int32_t index, void* userdata)
{
    (void)index;

    if (userdata == NULL)
        return false;

    int* dest = userdata;
    int64_t result = 0;

    if (!Streader_read_int(sr, &result))
        return false;

    *dest = (int)result;

    return true;
}
예제 #13
0
파일: Tuning_table.c 프로젝트: kagu/kunquat
static bool read_tuning_table_item(Streader* sr, const char* key, void* userdata)
{
    rassert(sr != NULL);
    rassert(key != NULL);
    rassert(userdata != NULL);

    Tuning_table* tt = userdata;

    if (string_eq(key, "ref_note"))
    {
        int64_t num = 0;
        if (!Streader_read_int(sr, &num))
            return false;

        if (num < 0 || num >= KQT_TUNING_TABLE_NOTES_MAX)
        {
            Streader_set_error(
                     sr, "Invalid reference note number: %" PRId64, num);
            return false;
        }

        tt->ref_note = (int)num;
    }
    else if (string_eq(key, "ref_pitch"))
    {
        double num = NAN;
        if (!Streader_read_float(sr, &num))
            return false;

        if (!isfinite(num))
        {
            Streader_set_error(sr, "Invalid reference pitch: %f", num);
            return false;
        }

        tt->ref_pitch = num;
    }
    else if (string_eq(key, "pitch_offset"))
    {
        double cents = NAN;
        if (!Streader_read_float(sr, &cents))
            return false;

        if (!isfinite(cents))
        {
            Streader_set_error(sr, "Pitch offset is not finite");
            return false;
        }

        tt->global_offset = cents;
    }
    else if (string_eq(key, "octave_width"))
    {
        double cents = NAN;
        if (!Streader_read_tuning(sr, &cents))
            return false;

        if (cents <= 0)
        {
            Streader_set_error(sr, "Octave width must be positive");
            return false;
        }

        Tuning_table_set_octave_width(tt, cents);
    }
    else if (string_eq(key, "centre_octave"))
    {
        int64_t octave = -1;
        if (!Streader_read_int(sr, &octave))
            return false;

        if (octave < 0 || octave >= KQT_TUNING_TABLE_OCTAVES)
        {
            Streader_set_error(sr, "Invalid centre octave: %" PRId64, octave);
            return false;
        }

        tt->centre_octave = (int)octave;
        Tuning_table_set_octave_width(tt, tt->octave_width);
    }
    else if (string_eq(key, "notes"))
    {
        for (int i = 0; i < KQT_TUNING_TABLE_NOTES_MAX; ++i)
            tt->note_offsets[i] = NAN;

        if (!Streader_read_list(sr, read_note, tt))
            return false;
    }
    else
    {
        Streader_set_error(sr, "Unrecognised key in tuning table: %s", key);
        return false;
    }

    return true;
}
예제 #14
0
bool Streader_readf(Streader* sr, const char* format, ...)
{
    rassert(sr != NULL);
    rassert(format != NULL);

    va_list args;
    va_start(args, format);

    while (!Streader_is_error_set(sr) && *format != '\0')
    {
        if (*format == '%')
        {
            // Conversion characters
            ++format;

            switch (*format)
            {
                case 'n':
                {
                    Streader_read_null(sr);
                }
                break;

                case 'b':
                {
                    bool* dest = va_arg(args, bool*);
                    Streader_read_bool(sr, dest);
                }
                break;

                case 'i':
                {
                    int64_t* dest = va_arg(args, int64_t*);
                    Streader_read_int(sr, dest);
                }
                break;

                case 'f':
                {
                    double* dest = va_arg(args, double*);
                    Streader_read_float(sr, dest);
                }
                break;

                case 's':
                {
                    Streader_readf_str_info info =
                        va_arg(args, Streader_readf_str_info);
                    rassert(info.guard == Streader_readf_str_guard);

                    const int64_t max_bytes = info.max_bytes;
                    char* dest = info.dest;
                    Streader_read_string(sr, max_bytes, dest);
                }
                break;

                case 't':
                {
                    Tstamp* dest = va_arg(args, Tstamp*);
                    Streader_read_tstamp(sr, dest);
                }
                break;

                case 'p':
                {
                    Pat_inst_ref* dest = va_arg(args, Pat_inst_ref*);
                    Streader_read_piref(sr, dest);
                }
                break;

                case 'l':
                {
                    List_item_reader* ir = va_arg(args, List_item_reader*);
                    void* userdata = va_arg(args, void*);
                    Streader_read_list(sr, ir, userdata);
                }
                break;

                case 'd':
                {
                    Dict_item_reader* ir = va_arg(args, Dict_item_reader*);
                    void* userdata = va_arg(args, void*);
                    Streader_read_dict(sr, ir, userdata);
                }
                break;

                case '%':
                {
                    Streader_match_char(sr, '%');
                }
                break;

                default:
                    rassert(false);
            }
        }
        else
        {
            // Characters to be matched
            if (!isspace(*format))
예제 #15
0
Env_var* new_Env_var_from_string(Streader* sr)
{
    rassert(sr != NULL);

    if (Streader_is_error_set(sr))
        return NULL;

    char type_name[16] = "";
    char name[KQT_VAR_NAME_MAX] = "";

    if (!Streader_readf(
                sr,
                "[%s,%s,",
                READF_STR(16, type_name),
                READF_STR(KQT_VAR_NAME_MAX, name)))
        return NULL;

    if (!is_valid_var_name(name))
    {
        Streader_set_error(
                sr,
                "Illegal variable name %s"
                    " (Variable names may only contain"
                    " lower-case letters and underscores"
                    " (and digits as other than first characters))",
                name);
        return NULL;
    }

    Value* value = VALUE_AUTO;

    if (string_eq(type_name, "bool"))
    {
        value->type = VALUE_TYPE_BOOL;
        Streader_read_bool(sr, &value->value.bool_type);
    }
    else if (string_eq(type_name, "int"))
    {
        value->type = VALUE_TYPE_INT;
        Streader_read_int(sr, &value->value.int_type);
    }
    else if (string_eq(type_name, "float"))
    {
        value->type = VALUE_TYPE_FLOAT;
        Streader_read_float(sr, &value->value.float_type);
    }
    else if (string_eq(type_name, "timestamp"))
    {
        value->type = VALUE_TYPE_TSTAMP;
        Streader_read_tstamp(sr, &value->value.Tstamp_type);
    }
    else
    {
        Streader_set_error(
                sr,
                "Invalid type of environment variable %s: %s",
                name,
                type_name);
        return NULL;
    }

    if (!Streader_match_char(sr, ']'))
        return NULL;

    Env_var* var = new_Env_var(value->type, name);
    if (var == NULL)
    {
        Streader_set_memory_error(
                sr, "Could not allocate memory for environment variable");
        return NULL;
    }

    Env_var_set_value(var, value);

    return var;
}