<commit_before>#include "exml.h"

static ErlNifResourceType *PARSER_POINTER = NULL;

void *start_element_handler(expat_parser *parser_data, const XML_Char *name, const XML_Char **atts)
{
    ErlNifBinary element_name;
    ERL_NIF_TERM attrs_list = enif_make_list(parser_data->env, 0);
    int i;

    enif_alloc_binary(strlen(name), &element_name);
    strcpy((char *) element_name.data, (const char *)name);

    for(i = 0; atts[i]; i += 2);
    while(i)
        {
            ErlNifBinary attr_name, attr_value;

            enif_alloc_binary(strlen(atts[i-1]), &attr_value);
            enif_alloc_binary(strlen(atts[i-2]), &attr_name);
            strcpy((char *) attr_value.data, (const char *)atts[i-1]);
            strcpy((char *) attr_name.data, (const char *)atts[i-2]);

            ERL_NIF_TERM attr = enif_make_tuple(parser_data->env, 2,
                                                enif_make_binary(parser_data->env, &attr_name),
                                                enif_make_binary(parser_data->env, &attr_value));
            attrs_list = enif_make_list_cell(parser_data->env, attr, attrs_list);

            i -= 2;
        };

    ERL_NIF_TERM event = enif_make_tuple(parser_data->env, 3,
                                         enif_make_atom(parser_data->env, "xml_element_start"),
                                         enif_make_binary(parser_data->env, &element_name),
                                         attrs_list);
    parser_data->result = enif_make_list_cell(parser_data->env, event, parser_data->result);

    return NULL;
};

void *end_element_handler(expat_parser *parser_data, const XML_Char *name)
{
    ErlNifBinary element_name;

    enif_alloc_binary(strlen(name), &element_name);
    strcpy((char *) element_name.data, (const char *)name);

    ERL_NIF_TERM event = enif_make_tuple(parser_data->env, 2,
                                         enif_make_atom(parser_data->env, "xml_element_end"),
                                         enif_make_binary(parser_data->env, &element_name));
    parser_data->result = enif_make_list_cell(parser_data->env, event, parser_data->result);

    return NULL;
};

void *character_data_handler(expat_parser *parser_data, const XML_Char *s, int len)
{
    ErlNifBinary cdata;

    enif_alloc_binary(len, &cdata);
    strcpy((char *) cdata.data, (const char *)s);

    ERL_NIF_TERM event = enif_make_tuple(parser_data->env, 2,
                                         enif_make_atom(parser_data->env, "xml_cdata"),
                                         enif_make_binary(parser_data->env, &cdata));
    parser_data->result = enif_make_list_cell(parser_data->env, event, parser_data->result);

    return NULL;
};

ERL_NIF_TERM new_parser(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
    XML_Parser parser;
    expat_parser *parser_data = (expat_parser *)enif_alloc(sizeof(expat_parser));
    ERL_NIF_TERM parser_resource;

    parser = XML_ParserCreate_MM("UTF-8", &ms, "\n");
    parser_data->env = env;

    XML_SetUserData(parser, parser_data);

    XML_SetStartElementHandler(parser, (XML_StartElementHandler)start_element_handler);
    XML_SetEndElementHandler(parser, (XML_EndElementHandler)end_element_handler);
    XML_SetCharacterDataHandler(parser, (XML_CharacterDataHandler)character_data_handler);

    XML_SetReturnNSTriplet(parser, 1);
    XML_SetDefaultHandler(parser, NULL);

    XML_Parser *xml_parser = (XML_Parser *)enif_alloc_resource(PARSER_POINTER, sizeof(XML_Parser));
    *xml_parser = parser;
    parser_resource = enif_make_resource(env, (void *)xml_parser);
    enif_release_resource(xml_parser);

    return enif_make_tuple(env, 2, enif_make_atom(env, "ok"), parser_resource);
};

ERL_NIF_TERM free_parser(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
    XML_Parser **parser;

    assert(argc == 1);

    if (!enif_get_resource(env, argv[0], PARSER_POINTER, (void **)&parser))
        return enif_make_badarg(env);

    expat_parser *parser_data = XML_GetUserData((XML_Parser)(*parser));
    enif_free(parser_data);

    return enif_make_atom(env, "ok");
};

ERL_NIF_TERM parse(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
    XML_Parser **parser;
    int is_final, res, errcode;
    ErlNifBinary stream;
    char *errstring;

    assert(argc == 3);

    if (!enif_get_resource(env, argv[0], PARSER_POINTER, (void **)&parser))
        return enif_make_badarg(env);

    if (!enif_is_binary(env, argv[1]))
        return enif_make_badarg(env);

    enif_get_int(env, argv[2], &is_final);
    enif_inspect_binary(env, argv[1], &stream);

    expat_parser *parser_data = XML_GetUserData((XML_Parser)(*parser));
    parser_data->result = enif_make_list(env, 0);
    XML_SetUserData((XML_Parser)(*parser), parser_data);

    res = XML_Parse((XML_Parser)(*parser), (const char *)stream.data, stream.size, is_final);
    if(!res)
        {
            errcode = XML_GetErrorCode((XML_Parser)(*parser));<commit_msg>Freeing parser instance in NIF<commit_after>#include "exml.h"

static ErlNifResourceType *PARSER_POINTER = NULL;

void *start_element_handler(expat_parser *parser_data, const XML_Char *name, const XML_Char **atts)
{
    ErlNifBinary element_name;
    ERL_NIF_TERM attrs_list = enif_make_list(parser_data->env, 0);
    int i;

    enif_alloc_binary(strlen(name), &element_name);
    strcpy((char *) element_name.data, (const char *)name);

    for(i = 0; atts[i]; i += 2);
    while(i)
        {
            ErlNifBinary attr_name, attr_value;

            enif_alloc_binary(strlen(atts[i-1]), &attr_value);
            enif_alloc_binary(strlen(atts[i-2]), &attr_name);
            strcpy((char *) attr_value.data, (const char *)atts[i-1]);
            strcpy((char *) attr_name.data, (const char *)atts[i-2]);

            ERL_NIF_TERM attr = enif_make_tuple(parser_data->env, 2,
                                                enif_make_binary(parser_data->env, &attr_name),
                                                enif_make_binary(parser_data->env, &attr_value));
            attrs_list = enif_make_list_cell(parser_data->env, attr, attrs_list);

            i -= 2;
        };

    ERL_NIF_TERM event = enif_make_tuple(parser_data->env, 3,
                                         enif_make_atom(parser_data->env, "xml_element_start"),
                                         enif_make_binary(parser_data->env, &element_name),
                                         attrs_list);
    parser_data->result = enif_make_list_cell(parser_data->env, event, parser_data->result);

    return NULL;
};

void *end_element_handler(expat_parser *parser_data, const XML_Char *name)
{
    ErlNifBinary element_name;

    enif_alloc_binary(strlen(name), &element_name);
    strcpy((char *) element_name.data, (const char *)name);

    ERL_NIF_TERM event = enif_make_tuple(parser_data->env, 2,
                                         enif_make_atom(parser_data->env, "xml_element_end"),
                                         enif_make_binary(parser_data->env, &element_name));
    parser_data->result = enif_make_list_cell(parser_data->env, event, parser_data->result);

    return NULL;
};

void *character_data_handler(expat_parser *parser_data, const XML_Char *s, int len)
{
    ErlNifBinary cdata;

    enif_alloc_binary(len, &cdata);
    strcpy((char *) cdata.data, (const char *)s);

    ERL_NIF_TERM event = enif_make_tuple(parser_data->env, 2,
                                         enif_make_atom(parser_data->env, "xml_cdata"),
                                         enif_make_binary(parser_data->env, &cdata));
    parser_data->result = enif_make_list_cell(parser_data->env, event, parser_data->result);

    return NULL;
};

ERL_NIF_TERM new_parser(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
    XML_Parser parser;
    expat_parser *parser_data = (expat_parser *)enif_alloc(sizeof(expat_parser));
    ERL_NIF_TERM parser_resource;

    parser = XML_ParserCreate_MM("UTF-8", &ms, "\n");
    parser_data->env = env;

    XML_SetUserData(parser, parser_data);

    XML_SetStartElementHandler(parser, (XML_StartElementHandler)start_element_handler);
    XML_SetEndElementHandler(parser, (XML_EndElementHandler)end_element_handler);
    XML_SetCharacterDataHandler(parser, (XML_CharacterDataHandler)character_data_handler);

    XML_SetReturnNSTriplet(parser, 1);
    XML_SetDefaultHandler(parser, NULL);

    XML_Parser *xml_parser = (XML_Parser *)enif_alloc_resource(PARSER_POINTER, sizeof(XML_Parser));
    *xml_parser = parser;
    parser_resource = enif_make_resource(env, (void *)xml_parser);
    enif_release_resource(xml_parser);

    return enif_make_tuple(env, 2, enif_make_atom(env, "ok"), parser_resource);
};

ERL_NIF_TERM free_parser(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
    XML_Parser **parser;

    assert(argc == 1);

    if (!enif_get_resource(env, argv[0], PARSER_POINTER, (void **)&parser))
        return enif_make_badarg(env);

    expat_parser *parser_data = XML_GetUserData((XML_Parser)(*parser));
    enif_free(parser_data);

    XML_ParserFree((XML_Parser)(*parser));

    return enif_make_atom(env, "ok");
};

ERL_NIF_TERM parse(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
    XML_Parser **parser;
    int is_final, res, errcode;
    ErlNifBinary stream;
    char *errstring;

    assert(argc == 3);

    if (!enif_get_resource(env, argv[0], PARSER_POINTER, (void **)&parser))
        return enif_make_badarg(env);

    if (!enif_is_binary(env, argv[1]))
        return enif_make_badarg(env);

    enif_get_int(env, argv[2], &is_final);
    enif_inspect_binary(env, argv[1], &stream);

    expat_parser *parser_data = XML_GetUserData((XML_Parser)(*parser));
    parser_data->result = enif_make_list(env, 0);
    XML_SetUserData((XML_Parser)(*parser), parser_data);

    res = XML_Parse((XML_Parser)(*parser), (const char *)stream.data, stream.size, is_final);
    if(!res)
        {
            errcode = XML_GetErrorCode((XML_Parser)(*parser));
{'fraction_non_alphanumeric': 0.11890701631468321, 'fraction_numerical': 0.0046041437293564205, 'mean_word_length': 3.253724989357173, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 16}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 36, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '169248', 'n_tokens_mistral': 3408, 'n_tokens_neox': 3350, 'n_words': 560}