Пример #1
0
/*
 * This is the main function for dumping any node.
 */
SV *
load_node(perl_yaml_loader_t *loader)
{
    /* Get the next parser event */
    if (!yaml_parser_parse(&loader->parser, &loader->event))
        goto load_error;

    /* Return NULL when we hit the end of a scope */
    if (loader->event.type == YAML_DOCUMENT_END_EVENT ||
        loader->event.type == YAML_MAPPING_END_EVENT ||
        loader->event.type == YAML_SEQUENCE_END_EVENT) return NULL;

    /* Handle loading a mapping */
    if (loader->event.type == YAML_MAPPING_START_EVENT) {
        SV *hash_ref;
        char *tag = (char *)loader->event.data.mapping_start.tag;

        /* Handle mapping tagged as a Perl hard reference */
        if (tag && strEQ(tag, TAG_PERL_REF))
            return load_scalar_ref(loader);
        
        /* Handle mapping tagged as a Perl typeglob */
        if (tag && strEQ(tag, TAG_PERL_GLOB))
            return load_glob(loader);

        /* Load the mapping into a hash ref and return it */
        return load_mapping(loader, NULL);
    }

    /* Handle loading a sequence into an array */
    if (loader->event.type == YAML_SEQUENCE_START_EVENT)
        return load_sequence(loader);

    /* Handle loading a scalar */
    if (loader->event.type == YAML_SCALAR_EVENT)
        return load_scalar(loader);

    /* Handle loading an alias node */
    if (loader->event.type == YAML_ALIAS_EVENT)
        return load_alias(loader);

    /* Some kind of error occurred */
    if (loader->event.type == YAML_NO_EVENT)
        croak(loader_error_msg(loader, NULL));

    croak(ERRMSG "Invalid event '%d' at top level", (int) loader->event.type);

load_error:
    croak(loader_error_msg(loader, NULL));
}
Пример #2
0
/* Load a YAML sequence into a Perl array */
SV *
load_sequence(perl_yaml_loader_t *loader)
{
    SV *node;
    AV *array = newAV();
    SV *array_ref = (SV *)newRV_noinc((SV *)array);
    char *anchor = (char *)loader->event.data.sequence_start.anchor;
    char *tag = (char *)loader->event.data.mapping_start.tag;
    if (anchor)
        hv_store(loader->anchors, anchor, strlen(anchor), SvREFCNT_inc(array_ref), 0);
    while ((node = load_node(loader))) {
        av_push(array, node);
    } 
    if (tag && strEQ(tag, TAG_PERL_PREFIX "array"))
        tag = NULL;
    if (tag) {
        char *class;
        char *prefix = TAG_PERL_PREFIX "array:";
        if (*tag == '!')
            prefix = "!";
        else if (strlen(tag) <= strlen(prefix) ||
            ! strnEQ(tag, prefix, strlen(prefix))
        ) croak(
            loader_error_msg(loader, form("bad tag found for array: '%s'", tag))
        );
        class = tag + strlen(prefix);
        sv_bless(array_ref, gv_stashpv(class, TRUE)); 
    }
    return array_ref;
}
Пример #3
0
/*
 * Load a YAML mapping into a Perl hash
 */
SV *
load_mapping(perl_yaml_loader_t *loader, char *tag)
{
    SV *key_node;
    SV *value_node;
    HV *hash = newHV();
    SV *hash_ref = (SV *)newRV_noinc((SV *)hash);
    char *anchor = (char *)loader->event.data.mapping_start.anchor;

    if (!tag)
        tag = (char *)loader->event.data.mapping_start.tag;

    /* Store the anchor label if any */
    if (anchor)
        hv_store(loader->anchors, anchor, strlen(anchor), SvREFCNT_inc(hash_ref), 0);

    /* Get each key string and value node and put them in the hash */
    while ((key_node = load_node(loader))) {
        assert(SvPOK(key_node));
        value_node = load_node(loader);
        hv_store_ent(
            hash, key_node, value_node, 0
        );
    } 

    /* Deal with possibly blessing the hash if the YAML tag has a class */
    if (tag && strEQ(tag, TAG_PERL_PREFIX "hash"))
        tag = NULL;
    if (tag) {
        char *class;
        char *prefix = TAG_PERL_PREFIX "hash:";
        if (*tag == '!') {
            prefix = "!";
        }
        else if (strlen(tag) <= strlen(prefix) ||
            ! strnEQ(tag, prefix, strlen(prefix))
        ) croak(
            loader_error_msg(loader, form("bad tag found for hash: '%s'", tag))
        );
        class = tag + strlen(prefix);
        sv_bless(hash_ref, gv_stashpv(class, TRUE)); 
    }

    return hash_ref;
}
Пример #4
0
/*
 * This is the main Load function.
 * It takes a yaml stream and turns it into 0 or more Perl objects.
 */
void
Load(SV *yaml_sv)
{
    dXSARGS;
    perl_yaml_loader_t loader;
    SV *node;
    char *yaml_str;
    STRLEN yaml_len;
    
    /* If UTF8, make copy and downgrade */
    if (SvPV_nolen(yaml_sv) && SvUTF8(yaml_sv)) {
        yaml_sv = sv_mortalcopy(yaml_sv);
    }
    yaml_str = SvPVbyte(yaml_sv, yaml_len);

    sp = mark;
    if (0 && (items || ax)) {} /* XXX Quiet the -Wall warnings for now. */

    yaml_parser_initialize(&loader.parser);
    loader.document = 0;
    yaml_parser_set_input_string(
        &loader.parser,
        (unsigned char *)yaml_str,
        yaml_len
    );

    /* Get the first event. Must be a STREAM_START */
    if (!yaml_parser_parse(&loader.parser, &loader.event))
        goto load_error;
    if (loader.event.type != YAML_STREAM_START_EVENT)
        croak(ERRMSG "Expected STREAM_START_EVENT; Got: %d != %d",
            loader.event.type,
            YAML_STREAM_START_EVENT
         );

    loader.anchors = newHV();
    sv_2mortal((SV*)loader.anchors);

    /* Keep calling load_node until end of stream */
    while (1) {
        loader.document++;
        if (!yaml_parser_parse(&loader.parser, &loader.event))
            goto load_error;
        if (loader.event.type == YAML_STREAM_END_EVENT)
            break;
        node = load_node(&loader);
        hv_clear(loader.anchors);
        if (! node) break;
        XPUSHs(sv_2mortal(node));
        if (!yaml_parser_parse(&loader.parser, &loader.event))
            goto load_error;
        if (loader.event.type != YAML_DOCUMENT_END_EVENT)
            croak(ERRMSG "Expected DOCUMENT_END_EVENT");
    }

    /* Make sure the last event is a STREAM_END */
    if (loader.event.type != YAML_STREAM_END_EVENT)
        croak(ERRMSG "Expected STREAM_END_EVENT; Got: %d != %d",
            loader.event.type,
            YAML_STREAM_END_EVENT
         );
    yaml_parser_delete(&loader.parser);
    PUTBACK;
    return;

load_error:
    croak(loader_error_msg(&loader, NULL));
}
Пример #5
0
/*
 * This is the main function for dumping any node.
 */
SV *
load_node(perl_yaml_loader_t *loader)
{
    SV* return_sv = NULL;
    /* This uses stack, but avoids (severe!) memory leaks */
    yaml_event_t uplevel_event;

    uplevel_event = loader->event;

    /* Get the next parser event */
    if (!yaml_parser_parse(&loader->parser, &loader->event))
        goto load_error;

    /* These events don't need yaml_event_delete */
    /* Some kind of error occurred */
    if (loader->event.type == YAML_NO_EVENT)
        goto load_error;

    /* Return NULL when we hit the end of a scope */
    if (loader->event.type == YAML_DOCUMENT_END_EVENT ||
        loader->event.type == YAML_MAPPING_END_EVENT ||
        loader->event.type == YAML_SEQUENCE_END_EVENT) {
            /* restore the uplevel event, so it can be properly deleted */
            loader->event = uplevel_event;
            return return_sv;
    }

    /* The rest all need cleanup */
    switch (loader->event.type) {
        char *tag;

        /* Handle loading a mapping */
        case YAML_MAPPING_START_EVENT:
            tag = (char *)loader->event.data.mapping_start.tag;

            /* Handle mapping tagged as a Perl hard reference */
            if (tag && strEQ(tag, TAG_PERL_REF)) {
                return_sv = load_scalar_ref(loader);
                break;
            }

            /* Handle mapping tagged as a Perl typeglob */
            if (tag && strEQ(tag, TAG_PERL_GLOB)) {
                return_sv = load_glob(loader);
                break;
            }

            return_sv = load_mapping(loader, NULL);
            break;

        /* Handle loading a sequence into an array */
        case YAML_SEQUENCE_START_EVENT:
            return_sv = load_sequence(loader);
            break;

        /* Handle loading a scalar */
        case YAML_SCALAR_EVENT:
            return_sv = load_scalar(loader);
            break;

        /* Handle loading an alias node */
        case YAML_ALIAS_EVENT:
            return_sv = load_alias(loader);
            break;

        default:
            croak("%sInvalid event '%d' at top level", ERRMSG, (int) loader->event.type);
    }

    yaml_event_delete(&loader->event);

    /* restore the uplevel event, so it can be properly deleted */
    loader->event = uplevel_event;

    return return_sv;

    load_error:
        croak("%s", loader_error_msg(loader, NULL));
}
Пример #6
0
/*
 * This is the main Load function.
 * It takes a yaml stream and turns it into 0 or more Perl objects.
 */
void
Load(SV *yaml_sv)
{
    dXSARGS;
    perl_yaml_loader_t loader;
    SV *node;
    const unsigned char *yaml_str;
    STRLEN yaml_len;

    yaml_str = (const unsigned char *)SvPV_const(yaml_sv, yaml_len);

    if (DO_UTF8(yaml_sv)) {
        yaml_sv = sv_mortalcopy(yaml_sv);
        if (!sv_utf8_downgrade(yaml_sv, TRUE))
            croak("%s", "Wide character in YAML::XS::Load()");
        yaml_str = (const unsigned char *)SvPV_const(yaml_sv, yaml_len);
    }

    sp = mark;
    if (0 && (items || ax)) {} /* XXX Quiet the -Wall warnings for now. */

    yaml_parser_initialize(&loader.parser);
    loader.document = 0;
    yaml_parser_set_input_string(
        &loader.parser,
        yaml_str,
        yaml_len
    );

    /* Get the first event. Must be a STREAM_START */
    if (!yaml_parser_parse(&loader.parser, &loader.event))
        goto load_error;
    if (loader.event.type != YAML_STREAM_START_EVENT)
        croak("%sExpected STREAM_START_EVENT; Got: %d != %d",
            ERRMSG,
            loader.event.type,
            YAML_STREAM_START_EVENT
         );

    loader.anchors = newHV();
    sv_2mortal((SV *)loader.anchors);

    /* Keep calling load_node until end of stream */
    while (1) {
        loader.document++;
        /* We are through with the previous event - delete it! */
        yaml_event_delete(&loader.event);
        if (!yaml_parser_parse(&loader.parser, &loader.event))
            goto load_error;
        if (loader.event.type == YAML_STREAM_END_EVENT)
            break;
        node = load_node(&loader);
        /* We are through with the previous event - delete it! */
        yaml_event_delete(&loader.event);
        hv_clear(loader.anchors);
        if (! node) break;
        XPUSHs(sv_2mortal(node));
        if (!yaml_parser_parse(&loader.parser, &loader.event))
            goto load_error;
        if (loader.event.type != YAML_DOCUMENT_END_EVENT)
            croak("%sExpected DOCUMENT_END_EVENT", ERRMSG);
    }

    /* Make sure the last event is a STREAM_END */
    if (loader.event.type != YAML_STREAM_END_EVENT)
        croak("%sExpected STREAM_END_EVENT; Got: %d != %d",
            ERRMSG,
            loader.event.type,
            YAML_STREAM_END_EVENT
         );
    yaml_parser_delete(&loader.parser);
    PUTBACK;
    return;

load_error:
    croak("%s", loader_error_msg(&loader, NULL));
}