static const char *skip_space(const char *s)
{
    while (ossl_isspace(*s))
        s++;
    return s;
}
['static int test_property(void)\n{\n    static const struct {\n        int nid;\n        const char *prop;\n        char *impl;\n    } impls[] = {\n        { 1, "fast=no, colour=green", "a" },\n        { 1, "fast, colour=blue", "b" },\n        { 1, "", "-" },\n        { 9, "sky=blue, furry", "c" },\n        { 3, NULL, "d" },\n        { 6, "sky.colour=blue, sky=green, old.data", "e" },\n    };\n    static struct {\n        int nid;\n        const char *prop;\n        char *expected;\n    } queries[] = {\n        { 1, "fast", "b" },\n        { 1, "fast=yes", "b" },\n        { 1, "fast=no, colour=green", "a" },\n        { 1, "colour=blue, fast", "b" },\n        { 1, "colour=blue", "b" },\n        { 9, "furry", "c" },\n        { 6, "sky.colour=blue", "e" },\n        { 6, "old.data", "e" },\n        { 9, "furry=yes, sky=blue", "c" },\n        { 1, "", "a" },\n        { 3, "", "d" },\n    };\n    OSSL_METHOD_STORE *store;\n    size_t i;\n    int ret = 0;\n    void *result;\n    if (!TEST_ptr(store = ossl_method_store_new(NULL))\n        || !add_property_names("fast", "colour", "sky", "furry", NULL))\n        goto err;\n    for (i = 0; i < OSSL_NELEM(impls); i++)\n        if (!TEST_true(ossl_method_store_add(store, NULL, impls[i].nid,\n                                             impls[i].prop, impls[i].impl,\n                                             NULL, NULL))) {\n            TEST_note("iteration %zd", i + 1);\n            goto err;\n        }\n    for (i = 0; i < OSSL_NELEM(queries); i++) {\n        OSSL_PROPERTY_LIST *pq = NULL;\n        if (!TEST_true(ossl_method_store_fetch(store, queries[i].nid,\n                                               queries[i].prop, &result))\n            || !TEST_str_eq((char *)result, queries[i].expected)) {\n            TEST_note("iteration %zd", i + 1);\n            ossl_property_free(pq);\n            goto err;\n        }\n        ossl_property_free(pq);\n    }\n    ret = 1;\nerr:\n    ossl_method_store_free(store);\n    return ret;\n}', 'int ossl_method_store_add(OSSL_METHOD_STORE *store, const OSSL_PROVIDER *prov,\n                          int nid, const char *properties, void *method,\n                          int (*method_up_ref)(void *),\n                          void (*method_destruct)(void *))\n{\n    ALGORITHM *alg = NULL;\n    IMPLEMENTATION *impl;\n    int ret = 0;\n    int i;\n    if (nid <= 0 || method == NULL || store == NULL)\n        return 0;\n    if (properties == NULL)\n        properties = "";\n    impl = OPENSSL_malloc(sizeof(*impl));\n    if (impl == NULL)\n        return 0;\n    if (method_up_ref != NULL && !method_up_ref(method)) {\n        OPENSSL_free(impl);\n        return 0;\n    }\n    impl->provider = prov;\n    impl->method = method;\n    impl->method_destruct = method_destruct;\n    ossl_property_write_lock(store);\n    ossl_method_cache_flush(store, nid);\n    if ((impl->properties = ossl_prop_defn_get(store->ctx, properties)) == NULL) {\n        impl->properties = ossl_parse_property(store->ctx, properties);\n        if (impl->properties == NULL)\n            goto err;\n        ossl_prop_defn_set(store->ctx, properties, impl->properties);\n    }\n    alg = ossl_method_store_retrieve(store, nid);\n    if (alg == NULL) {\n        if ((alg = OPENSSL_zalloc(sizeof(*alg))) == NULL\n                || (alg->impls = sk_IMPLEMENTATION_new_null()) == NULL\n                || (alg->cache = lh_QUERY_new(&query_hash, &query_cmp)) == NULL)\n            goto err;\n        alg->nid = nid;\n        if (!ossl_method_store_insert(store, alg))\n            goto err;\n    }\n    for (i = 0; i < sk_IMPLEMENTATION_num(alg->impls); i++) {\n        const IMPLEMENTATION *tmpimpl = sk_IMPLEMENTATION_value(alg->impls, i);\n        if (tmpimpl->provider == impl->provider\n            && tmpimpl->properties == impl->properties)\n            break;\n    }\n    if (i == sk_IMPLEMENTATION_num(alg->impls)\n        && sk_IMPLEMENTATION_push(alg->impls, impl))\n        ret = 1;\n    ossl_property_unlock(store);\n    if (ret == 0)\n        impl_free(impl);\n    return ret;\nerr:\n    ossl_property_unlock(store);\n    alg_cleanup(0, alg);\n    impl_free(impl);\n    return 0;\n}', 'OSSL_PROPERTY_LIST *ossl_parse_property(OPENSSL_CTX *ctx, const char *defn)\n{\n    PROPERTY_DEFINITION *prop = NULL;\n    OSSL_PROPERTY_LIST *res = NULL;\n    STACK_OF(PROPERTY_DEFINITION) *sk;\n    const char *s = defn;\n    int done;\n    if (s == NULL || (sk = sk_PROPERTY_DEFINITION_new(&pd_compare)) == NULL)\n        return NULL;\n    s = skip_space(s);\n    done = *s == \'\\0\';\n    while (!done) {\n        const char *start = s;\n        prop = OPENSSL_malloc(sizeof(*prop));\n        if (prop == NULL)\n            goto err;\n        memset(&prop->v, 0, sizeof(prop->v));\n        prop->optional = 0;\n        if (!parse_name(ctx, &s, 1, &prop->name_idx))\n            goto err;\n        prop->oper = PROPERTY_OPER_EQ;\n        if (prop->name_idx == 0) {\n            ERR_raise_data(ERR_LIB_PROP, PROP_R_PARSE_FAILED,\n                           "Unknown name HERE-->%s", start);\n            goto err;\n        }\n        if (match_ch(&s, \'=\')) {\n            if (!parse_value(ctx, &s, prop, 1)) {\n                ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_VALUE,\n                               "HERE-->%s", start);\n                goto err;\n            }\n        } else {\n            prop->type = PROPERTY_TYPE_STRING;\n            prop->v.str_val = ossl_property_true;\n        }\n        if (!sk_PROPERTY_DEFINITION_push(sk, prop))\n            goto err;\n        prop = NULL;\n        done = !match_ch(&s, \',\');\n    }\n    if (*s != \'\\0\') {\n        ERR_raise_data(ERR_LIB_PROP, PROP_R_TRAILING_CHARACTERS,\n                       "HERE-->%s", s);\n        goto err;\n    }\n    res = stack_to_property_list(sk);\nerr:\n    OPENSSL_free(prop);\n    sk_PROPERTY_DEFINITION_pop_free(sk, &pd_free);\n    return res;\n}', 'static const char *skip_space(const char *s)\n{\n    while (ossl_isspace(*s))\n        s++;\n    return s;\n}', 'static int parse_name(OPENSSL_CTX *ctx, const char *t[], int create,\n                      OSSL_PROPERTY_IDX *idx)\n{\n    char name[100];\n    int err = 0;\n    size_t i = 0;\n    const char *s = *t;\n    int user_name = 0;\n    for (;;) {\n        if (!ossl_isalpha(*s)) {\n            ERR_raise_data(ERR_LIB_PROP, PROP_R_NOT_AN_IDENTIFIER,\n                           "HERE-->%s", *t);\n            return 0;\n        }\n        do {\n            if (i < sizeof(name) - 1)\n                name[i++] = ossl_tolower(*s);\n            else\n                err = 1;\n        } while (*++s == \'_\' || ossl_isalnum(*s));\n        if (*s != \'.\')\n            break;\n        user_name = 1;\n        if (i < sizeof(name) - 1)\n            name[i++] = *s;\n        else\n            err = 1;\n        s++;\n    }\n    name[i] = \'\\0\';\n    if (err) {\n        ERR_raise_data(ERR_LIB_PROP, PROP_R_NAME_TOO_LONG, "HERE-->%s", *t);\n        return 0;\n    }\n    *t = skip_space(s);\n    *idx = ossl_property_name(ctx, name, user_name && create);\n    return 1;\n}', 'static int match_ch(const char *t[], char m)\n{\n    const char *s = *t;\n    if (*s == m) {\n        *t = skip_space(s + 1);\n        return 1;\n    }\n    return 0;\n}', 'static int parse_value(OPENSSL_CTX *ctx, const char *t[],\n                       PROPERTY_DEFINITION *res, int create)\n{\n    const char *s = *t;\n    int r = 0;\n    if (*s == \'"\' || *s == \'\\\'\') {\n        s++;\n        r = parse_string(ctx, &s, s[-1], res, create);\n    } else if (*s == \'+\') {\n        s++;\n        r = parse_number(&s, res);\n    } else if (*s == \'-\') {\n        s++;\n        r = parse_number(&s, res);\n        res->v.int_val = -res->v.int_val;\n    } else if (*s == \'0\' && s[1] == \'x\') {\n        s += 2;\n        r = parse_hex(&s, res);\n    } else if (*s == \'0\' && ossl_isdigit(s[1])) {\n        s++;\n        r = parse_oct(&s, res);\n    } else if (ossl_isdigit(*s)) {\n        return parse_number(t, res);\n    } else if (ossl_isalpha(*s))\n        return parse_unquoted(ctx, t, res, create);\n    if (r)\n        *t = s;\n    return r;\n}', 'static int parse_string(OPENSSL_CTX *ctx, const char *t[], char delim,\n                        PROPERTY_DEFINITION *res, const int create)\n{\n    char v[1000];\n    const char *s = *t;\n    size_t i = 0;\n    int err = 0;\n    while (*s != \'\\0\' && *s != delim) {\n        if (i < sizeof(v) - 1)\n            v[i++] = *s;\n        else\n            err = 1;\n        s++;\n    }\n    if (*s == \'\\0\') {\n        ERR_raise_data(ERR_LIB_PROP, PROP_R_NO_MATCHING_STRING_DELIMETER,\n                       "HERE-->%c%s", delim, *t);\n        return 0;\n    }\n    v[i] = \'\\0\';\n    if (err) {\n        ERR_raise_data(ERR_LIB_PROP, PROP_R_STRING_TOO_LONG, "HERE-->%s", *t);\n    } else {\n        res->v.str_val = ossl_property_value(ctx, v, create);\n    }\n    *t = skip_space(s + 1);\n    res->type = PROPERTY_TYPE_STRING;\n    return !err;\n}']