static int append_buf(char **buf, int *size, const char *s)
{
    const int expand = 256;
    int len = strlen(s) + 1;
    char *p = *buf;
    if (p == NULL) {
        *size = ((len + expand - 1) / expand) * expand;
        p = *buf = app_malloc(*size, "engine buffer");
    } else {
        const int blen = strlen(p);
        if (blen > 0)
            len += 2 + blen;
        if (len > *size) {
            *size = ((len + expand - 1) / expand) * expand;
            p = OPENSSL_realloc(p, *size);
            if (p == NULL) {
                OPENSSL_free(*buf);
                *buf = NULL;
                return 0;
            }
            *buf = p;
        }
        if (blen > 0) {
            p += blen;
            *p++ = ',';
            *p++ = ' ';
        }
    }
    strcpy(p, s);
    return 1;
}
['int engine_main(int argc, char **argv)\n{\n    int ret = 1, i;\n    int verbose = 0, list_cap = 0, test_avail = 0, test_avail_noise = 0;\n    ENGINE *e;\n    STACK_OF(OPENSSL_CSTRING) *engines = sk_OPENSSL_CSTRING_new_null();\n    STACK_OF(OPENSSL_STRING) *pre_cmds = sk_OPENSSL_STRING_new_null();\n    STACK_OF(OPENSSL_STRING) *post_cmds = sk_OPENSSL_STRING_new_null();\n    BIO *out;\n    const char *indent = "     ";\n    OPTION_CHOICE o;\n    char *prog;\n    char *argv1;\n    out = dup_bio_out(FORMAT_TEXT);\n    if (engines == NULL || pre_cmds == NULL || post_cmds == NULL)\n        goto end;\n    prog = argv[0];\n    while ((argv1 = argv[1]) != NULL && *argv1 != \'-\') {\n        sk_OPENSSL_CSTRING_push(engines, argv1);\n        argc--;\n        argv++;\n    }\n    argv[0] = prog;\n    opt_init(argc, argv, engine_options);\n    while ((o = opt_next()) != OPT_EOF) {\n        switch (o) {\n        case OPT_EOF:\n        case OPT_ERR:\n            BIO_printf(bio_err, "%s: Use -help for summary.\\n", prog);\n            goto end;\n        case OPT_HELP:\n            opt_help(engine_options);\n            ret = 0;\n            goto end;\n        case OPT_VVVV:\n        case OPT_VVV:\n        case OPT_VV:\n        case OPT_V:\n            i = (int)(o - OPT_V) + 1;\n            if (verbose < i)\n                verbose = i;\n            break;\n        case OPT_C:\n            list_cap = 1;\n            break;\n        case OPT_TT:\n            test_avail_noise++;\n        case OPT_T:\n            test_avail++;\n            break;\n        case OPT_PRE:\n            sk_OPENSSL_STRING_push(pre_cmds, opt_arg());\n            break;\n        case OPT_POST:\n            sk_OPENSSL_STRING_push(post_cmds, opt_arg());\n            break;\n        }\n    }\n    argc = opt_num_rest();\n    argv = opt_rest();\n    for ( ; *argv; argv++) {\n        if (**argv == \'-\') {\n            BIO_printf(bio_err, "%s: Cannot mix flags and engine names.\\n",\n                       prog);\n            BIO_printf(bio_err, "%s: Use -help for summary.\\n", prog);\n            goto end;\n        }\n        sk_OPENSSL_CSTRING_push(engines, *argv);\n    }\n    if (sk_OPENSSL_CSTRING_num(engines) == 0) {\n        for (e = ENGINE_get_first(); e != NULL; e = ENGINE_get_next(e)) {\n            sk_OPENSSL_CSTRING_push(engines, ENGINE_get_id(e));\n        }\n    }\n    ret = 0;\n    for (i = 0; i < sk_OPENSSL_CSTRING_num(engines); i++) {\n        const char *id = sk_OPENSSL_CSTRING_value(engines, i);\n        if ((e = ENGINE_by_id(id)) != NULL) {\n            const char *name = ENGINE_get_name(e);\n            BIO_printf(out, "(%s) %s\\n", id, name);\n            util_do_cmds(e, pre_cmds, out, indent);\n            if (strcmp(ENGINE_get_id(e), id) != 0) {\n                BIO_printf(out, "Loaded: (%s) %s\\n",\n                           ENGINE_get_id(e), ENGINE_get_name(e));\n            }\n            if (list_cap) {\n                int cap_size = 256;\n                char *cap_buf = NULL;\n                int k, n;\n                const int *nids;\n                ENGINE_CIPHERS_PTR fn_c;\n                ENGINE_DIGESTS_PTR fn_d;\n                ENGINE_PKEY_METHS_PTR fn_pk;\n                if (ENGINE_get_RSA(e) != NULL\n                    && !append_buf(&cap_buf, &cap_size, "RSA"))\n                    goto end;\n                if (ENGINE_get_DSA(e) != NULL\n                    && !append_buf(&cap_buf, &cap_size, "DSA"))\n                    goto end;\n                if (ENGINE_get_DH(e) != NULL\n                    && !append_buf(&cap_buf, &cap_size, "DH"))\n                    goto end;\n                if (ENGINE_get_RAND(e) != NULL\n                    && !append_buf(&cap_buf, &cap_size, "RAND"))\n                    goto end;\n                fn_c = ENGINE_get_ciphers(e);\n                if (fn_c == NULL)\n                    goto skip_ciphers;\n                n = fn_c(e, NULL, &nids, 0);\n                for (k = 0; k < n; ++k)\n                    if (!append_buf(&cap_buf, &cap_size, OBJ_nid2sn(nids[k])))\n                        goto end;\n skip_ciphers:\n                fn_d = ENGINE_get_digests(e);\n                if (fn_d == NULL)\n                    goto skip_digests;\n                n = fn_d(e, NULL, &nids, 0);\n                for (k = 0; k < n; ++k)\n                    if (!append_buf(&cap_buf, &cap_size, OBJ_nid2sn(nids[k])))\n                        goto end;\n skip_digests:\n                fn_pk = ENGINE_get_pkey_meths(e);\n                if (fn_pk == NULL)\n                    goto skip_pmeths;\n                n = fn_pk(e, NULL, &nids, 0);\n                for (k = 0; k < n; ++k)\n                    if (!append_buf(&cap_buf, &cap_size, OBJ_nid2sn(nids[k])))\n                        goto end;\n skip_pmeths:\n                {\n                    struct util_store_cap_data store_ctx;\n                    store_ctx.engine = e;\n                    store_ctx.cap_buf = &cap_buf;\n                    store_ctx.cap_size = &cap_size;\n                    store_ctx.ok = 1;\n                    OSSL_STORE_do_all_loaders(util_store_cap, &store_ctx);\n                    if (!store_ctx.ok)\n                        goto end;\n                }\n                if (cap_buf != NULL && (*cap_buf != \'\\0\'))\n                    BIO_printf(out, " [%s]\\n", cap_buf);\n                OPENSSL_free(cap_buf);\n            }\n            if (test_avail) {\n                BIO_printf(out, "%s", indent);\n                if (ENGINE_init(e)) {\n                    BIO_printf(out, "[ available ]\\n");\n                    util_do_cmds(e, post_cmds, out, indent);\n                    ENGINE_finish(e);\n                } else {\n                    BIO_printf(out, "[ unavailable ]\\n");\n                    if (test_avail_noise)\n                        ERR_print_errors_fp(stdout);\n                    ERR_clear_error();\n                }\n            }\n            if ((verbose > 0) && !util_verbose(e, verbose, out, indent))\n                goto end;\n            ENGINE_free(e);\n        } else {\n            ERR_print_errors(bio_err);\n            if (++ret > 127)\n                ret = 127;\n        }\n    }\n end:\n    ERR_print_errors(bio_err);\n    sk_OPENSSL_CSTRING_free(engines);\n    sk_OPENSSL_STRING_free(pre_cmds);\n    sk_OPENSSL_STRING_free(post_cmds);\n    BIO_free_all(out);\n    return (ret);\n}', 'static int append_buf(char **buf, int *size, const char *s)\n{\n    const int expand = 256;\n    int len = strlen(s) + 1;\n    char *p = *buf;\n    if (p == NULL) {\n        *size = ((len + expand - 1) / expand) * expand;\n        p = *buf = app_malloc(*size, "engine buffer");\n    } else {\n        const int blen = strlen(p);\n        if (blen > 0)\n            len += 2 + blen;\n        if (len > *size) {\n            *size = ((len + expand - 1) / expand) * expand;\n            p = OPENSSL_realloc(p, *size);\n            if (p == NULL) {\n                OPENSSL_free(*buf);\n                *buf = NULL;\n                return 0;\n            }\n            *buf = p;\n        }\n        if (blen > 0) {\n            p += blen;\n            *p++ = \',\';\n            *p++ = \' \';\n        }\n    }\n    strcpy(p, s);\n    return 1;\n}']