bool
sml_string_append_vprintf(struct sml_string *sml_string, const char *format,
    va_list ap)
{
    char *buf, *new_str;
    int len;
    bool r;

    ON_NULL_RETURN_VAL(sml_string, false);
    ON_NULL_RETURN_VAL(format, false);

    r = false;
    buf = NULL;

    len = _sml_string_create_formatted_str(&buf, format, ap);

    if (len < 0)
        goto exit;

    new_str = realloc(sml_string->str,
        sizeof(char) * (len + sml_string->len) + 1);
    if (!new_str)
        goto exit;
    memcpy(new_str + sml_string->len, buf, len + 1);
    sml_string->str = new_str;
    sml_string->len += len;
    r = true;
exit:
    free(buf);
    return r;
}
bool
sml_fuzzy_load_file(struct sml_fuzzy *fuzzy, const char *filename)
{
    fl::Engine *engine;
    uint16_t i, len;
    void *width;

    try {
        fl::FllImporter importer;
        engine = importer.fromFile(filename);

    } catch (fl::Exception e) {
        sml_critical("%s", e.getWhat().c_str());
        return false;
    }

    if (engine->numberOfInputVariables() == 0 ||
        engine->numberOfOutputVariables() == 0) {
        sml_critical("Input and output variables must be provided!");
        goto error;
    }

    if (engine->numberOfRuleBlocks() == 0) {
      sml_critical("Rule blocks must be provided!");
      goto error;
    }

    if (fuzzy->engine)
        delete (fl::Engine*) fuzzy->engine;

    fuzzy->engine = engine;
    fuzzy->input_list = (struct sml_variables_list*)&(engine->inputVariables());
    fuzzy->output_list = (struct sml_variables_list*)&(engine->outputVariables());
    fuzzy->input_terms_count = _calc_terms_count(engine->inputVariables());
    fuzzy->output_terms_count = _calc_terms_count(engine->outputVariables());
    _remove_rule_blocks(engine);

    sol_vector_clear(&fuzzy->input_terms_width);
    sol_vector_clear(&fuzzy->output_terms_width);

    len = engine->inputVariables().size();
    for (i = 0; i < len; i++) {
        width = sol_vector_append(&fuzzy->input_terms_width);
        ON_NULL_RETURN_VAL(width, false);
    }

    len = engine->outputVariables().size();
    for (i = 0; i < len; i++) {
        width = sol_vector_append(&fuzzy->output_terms_width);
        ON_NULL_RETURN_VAL(width, false);
    }
    return true;

error:
    delete engine;
    return false;
}
bool
sml_string_append_printf(struct sml_string *sml_string, const char *format, ...)
{
    va_list ap;
    bool r;

    ON_NULL_RETURN_VAL(sml_string, false);
    ON_NULL_RETURN_VAL(format, false);

    va_start(ap, format);
    r = sml_string_append_vprintf(sml_string, format, ap);
    va_end(ap);
    return r;
}
bool
sml_string_append(struct sml_string *sml_string, const char *str)
{
    size_t len;
    char *buf;

    ON_NULL_RETURN_VAL(sml_string, false);
    ON_NULL_RETURN_VAL(str, false);
    len = strlen(str);

    buf = realloc(sml_string->str, sizeof(char) * (len + sml_string->len + 1));
    if (!buf)
        return false;
    sml_string->str = buf;
    memcpy(sml_string->str + sml_string->len, str, len + 1);
    sml_string->len += len;
    return true;
}
struct sml_string *
sml_string_new(const char *str)
{
    struct sml_string *sml_string = calloc(1, sizeof(struct sml_string));

    ON_NULL_RETURN_VAL(sml_string, NULL);
    if (str) {
        sml_string->str = strdup(str);
        if (!sml_string->str) {
            free(sml_string);
            return NULL;
        }
        sml_string->len = strlen(str);
    }
    return sml_string;
}
const char *
sml_string_get_string(struct sml_string *sml_string)
{
    ON_NULL_RETURN_VAL(sml_string, NULL);
    return sml_string->str;
}
size_t
sml_string_length(struct sml_string *sml_string)
{
    ON_NULL_RETURN_VAL(sml_string, 0);
    return sml_string->len;
}