����JFIF��������� Mr.X
  
  __  __    __   __  _____      _            _          _____ _          _ _ 
 |  \/  |   \ \ / / |  __ \    (_)          | |        / ____| |        | | |
 | \  / |_ __\ V /  | |__) | __ ___   ____ _| |_ ___  | (___ | |__   ___| | |
 | |\/| | '__|> <   |  ___/ '__| \ \ / / _` | __/ _ \  \___ \| '_ \ / _ \ | |
 | |  | | |_ / . \  | |   | |  | |\ V / (_| | ||  __/  ____) | | | |  __/ | |
 |_|  |_|_(_)_/ \_\ |_|   |_|  |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1
 if you need WebShell for Seo everyday contact me on Telegram
 Telegram Address : @jackleet
        
        
For_More_Tools: Telegram: @jackleet | Bulk Smtp support mail sender | Business Mail Collector | Mail Bouncer All Mail | Bulk Office Mail Validator | Html Letter private



Upload:

Command:

deexcl@216.73.217.71: ~ $
#include <perl_libyaml.h>

#if (PERL_REVISION > 5) || (PERL_REVISION == 5 && PERL_VERSION >= 36)
#  define PERL_HAVE_BOOLEANS
#endif

static SV *
call_coderef(SV *code, AV *args)
{
    dSP;
    SV **svp;
    I32 count = (args && args != Nullav) ? av_len(args) : -1;
    I32 i;

    PUSHMARK(SP);
    for (i = 0; i <= count; i++) {
        if ((svp = av_fetch(args, i, FALSE))) {
            XPUSHs(*svp);
        }
    }
    PUTBACK;
    count = call_sv(code, G_ARRAY);
    SPAGAIN;

    return fold_results(count);
}

static SV *
fold_results(I32 count)
{
    dSP;
    SV *retval = &PL_sv_undef;

    if (count > 1) {
        /* convert multiple return items into a list reference */
        AV *av = newAV();
        SV *last_sv = &PL_sv_undef;
        SV *sv = &PL_sv_undef;
        I32 i;

        av_extend(av, count - 1);
        for(i = 1; i <= count; i++) {
            last_sv = sv;
            sv = POPs;
            if (SvOK(sv) && !av_store(av, count - i, SvREFCNT_inc(sv)))
                SvREFCNT_dec(sv);
        }
        PUTBACK;

        retval = sv_2mortal((SV *) newRV_noinc((SV *) av));

        if (!SvOK(sv) || sv == &PL_sv_undef) {
            /* if first element was undef, die */
            croak("%sCall error", ERRMSG);
        }
        return retval;

    }
    else {
        if (count)
            retval = POPs;
        PUTBACK;
        return retval;
    }
}

static SV *
find_coderef(char *perl_var)
{
    SV *coderef;

    if ((coderef = get_sv(perl_var, FALSE))
        && SvROK(coderef)
        && SvTYPE(SvRV(coderef)) == SVt_PVCV)
        return coderef;

    return NULL;
}

/*
 * Piece together a parser/loader error message
 */
char *
loader_error_msg(perl_yaml_loader_t *loader, char *problem)
{
    char *msg;
    if (!problem)
        problem = (char *)loader->parser.problem;
    msg = form(
        LOADERRMSG
        "%swas found at "
        "document: %d",
        (problem ? form("The problem:\n\n    %s\n\n", problem) : "A problem "),
        loader->document
    );
    if (
        loader->parser.problem_mark.line ||
        loader->parser.problem_mark.column
    )
        msg = form("%s, line: %lu, column: %lu\n",
            msg,
            (unsigned long)loader->parser.problem_mark.line + 1,
            (unsigned long)loader->parser.problem_mark.column + 1
        );
    else
        msg = form("%s\n", msg);
    if (loader->parser.context)
        msg = form("%s%s at line: %lu, column: %lu\n",
            msg,
            loader->parser.context,
            (unsigned long)loader->parser.context_mark.line + 1,
            (unsigned long)loader->parser.context_mark.column + 1
        );

    return msg;
}

/*
 * 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)
{
    dXCPT;

    dXSARGS;
    perl_yaml_loader_t loader;
    SV *node;
    const unsigned char *yaml_str;
    STRLEN yaml_len;

    GV *gv = gv_fetchpv("YAML::XS::Boolean", FALSE, SVt_PV);
    char* boolean = "";
    loader.load_bool_jsonpp = 0;
    loader.load_bool_boolean = 0;
    if (SvTRUE(GvSV(gv))) {
        boolean = SvPV_nolen(GvSV(gv));
        if (strEQ(boolean, "JSON::PP")) {
            loader.load_bool_jsonpp = 1;
            load_module(PERL_LOADMOD_NOIMPORT, newSVpv("JSON::PP", 0), Nullsv);
        }
        else if (strEQ(boolean, "boolean")) {
            loader.load_bool_boolean = 1;
            load_module(PERL_LOADMOD_NOIMPORT, newSVpv("boolean", 0), Nullsv);
        }
        else {
            croak("%s",
                "$YAML::XS::Boolean only accepts 'JSON::PP', 'boolean' or a false value");
        }
    }

    loader.load_code = (
        ((gv = gv_fetchpv("YAML::XS::UseCode", TRUE, SVt_PV)) &&
        SvTRUE(GvSV(gv)))
    ||
        ((gv = gv_fetchpv("YAML::XS::LoadCode", TRUE, SVt_PV)) &&
        SvTRUE(GvSV(gv)))
    );

    loader.load_blessed = 0;
    gv = gv_fetchpv("YAML::XS::LoadBlessed", FALSE, SVt_PV);
    if (SvOK(GvSV(gv)) && SvTRUE(GvSV(gv))) {
        loader.load_blessed = 1;
    }

    loader.forbid_duplicate_keys = 0;
    gv = gv_fetchpv("YAML::XS::ForbidDuplicateKeys", FALSE, SVt_PV);
    if (SvOK(GvSV(gv)) && SvTRUE(GvSV(gv))) {
        loader.forbid_duplicate_keys = 1;
    }

    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
    );

    XCPT_TRY_START {

        /* Get the first event. Must be a STREAM_START */
        if (!yaml_parser_parse(&loader.parser, &loader.event))
            croak("%s", loader_error_msg(&loader, NULL));
        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))
                croak("%s", loader_error_msg(&loader, NULL));
            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))
                croak("%s", loader_error_msg(&loader, NULL));
            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
             );

    } XCPT_TRY_END

    XCPT_CATCH
    {
        yaml_parser_delete(&loader.parser);
        XCPT_RETHROW;
    }

    yaml_parser_delete(&loader.parser);
    PUTBACK;
    return;
}

/*
 * This is the main function for dumping any node.
 */
SV *
load_node(perl_yaml_loader_t *loader)
{
    char *tag;
    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) {

        /* 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));
}

/*
 * Load a YAML mapping into a Perl hash
 */
SV *
load_mapping(perl_yaml_loader_t *loader, char *tag)
{
    dXCPT;
    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);

    XCPT_TRY_START {

        /* 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);
            if (loader->forbid_duplicate_keys &&
                hv_exists_ent(hash, key_node, 0)
            ) {
                croak(
                    "%s",
                    loader_error_msg(
                        loader,
                        form("Duplicate key '%s'", SvPV_nolen(key_node))
                    )
                );
            }
            hv_store_ent(
                hash, sv_2mortal(key_node), value_node, 0
            );
        }

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

    } XCPT_TRY_END

    XCPT_CATCH
    {
        SvREFCNT_dec(hash_ref);
        XCPT_RETHROW;
    }

    return hash_ref;
}

/* Load a YAML sequence into a Perl array */
SV *
load_sequence(perl_yaml_loader_t *loader)
{
    dXCPT;
    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;

    XCPT_TRY_START {

        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) {
            if (strEQ(tag, TAG_PERL_PREFIX "array")) {
            }
            else if (strEQ(tag, YAML_SEQ_TAG)) {
            }
            else {
                char *class;
                char *prefix = TAG_PERL_PREFIX "array:";

                if (*tag == '!')
                    prefix = "!";
                else if (strlen(tag) <= strlen(prefix) ||
                    ! strnEQ(tag, prefix, strlen(prefix))
                ) croak("%s",
                    loader_error_msg(loader, form("bad tag found for array: '%s'", tag))
                );
                if (loader->load_blessed) {
                    class = tag + strlen(prefix);
                    sv_bless(array_ref, gv_stashpv(class, TRUE));
                }
            }
        }

    } XCPT_TRY_END

    XCPT_CATCH
    {
        SvREFCNT_dec(array_ref);
        XCPT_RETHROW;
    }

    return array_ref;
}

/* Load a YAML scalar into a Perl scalar */
SV *
load_scalar(perl_yaml_loader_t *loader)
{
    SV *scalar;
    char *string = (char *)loader->event.data.scalar.value;
    STRLEN length = (STRLEN)loader->event.data.scalar.length;
    char *anchor = (char *)loader->event.data.scalar.anchor;
    char *tag = (char *)loader->event.data.scalar.tag;
    yaml_scalar_style_t style = loader->event.data.scalar.style;
    if (tag) {
        if (strEQ(tag, YAML_STR_TAG)) {
            style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
        }
        else if (strEQ(tag, YAML_INT_TAG) || strEQ(tag, YAML_FLOAT_TAG)) {
            /* TODO check int/float */
            scalar = newSVpvn(string, length);
            if ( looks_like_number(scalar) ) {
                /* numify */
                SvIV_please(scalar);
            }
            else {
                croak("%s",
                    loader_error_msg(loader, form("Invalid content found for !!int tag: '%s'", tag))
                );
            }
            if (anchor)
                hv_store(loader->anchors, anchor, strlen(anchor), SvREFCNT_inc(scalar), 0);
            return scalar;
        }
        else if (
            strEQ(tag, YAML_NULL_TAG)
            &&
            (strEQ(string, "~") || strEQ(string, "null") || strEQ(string, ""))
        ) {
            scalar = newSV(0);
            if (anchor)
                hv_store(loader->anchors, anchor, strlen(anchor), SvREFCNT_inc(scalar), 0);
            return scalar;
        }
        else {
            char *class;
            char *prefix = TAG_PERL_PREFIX "regexp";
            if (strnEQ(tag, prefix, strlen(prefix)))
                return load_regexp(loader);
            prefix = TAG_PERL_PREFIX "code";
            if (strnEQ(tag, prefix, strlen(prefix)))
                return load_code(loader);
            prefix = TAG_PERL_PREFIX "scalar:";
            if (*tag == '!')
                prefix = "!";
            else if (strlen(tag) <= strlen(prefix) ||
                ! strnEQ(tag, prefix, strlen(prefix))
            ) croak("%sbad tag found for scalar: '%s'", ERRMSG, tag);
            class = tag + strlen(prefix);
            if (loader->load_blessed)
                scalar = sv_setref_pvn(newSV(0), class, string, strlen(string));
            else
                scalar = newSVpvn(string, length);
            SvUTF8_on(scalar);
            if (anchor)
                hv_store(loader->anchors, anchor, strlen(anchor), SvREFCNT_inc(scalar), 0);
            return scalar;
        }
    }

    else if (style == YAML_PLAIN_SCALAR_STYLE) {
        if (strEQ(string, "~") || strEQ(string, "null") || strEQ(string, "")) {
            scalar = newSV(0);
            if (anchor)
                hv_store(loader->anchors, anchor, strlen(anchor), SvREFCNT_inc(scalar), 0);
            return scalar;
        }
        else if (strEQ(string, "true")) {
            if (loader->load_bool_jsonpp) {
                char *name = "JSON::PP::Boolean";
                scalar = newSV(1);
                scalar = sv_setref_iv(scalar, name, 1);
            }
            else if (loader->load_bool_boolean) {
                char *name = "boolean";
                scalar = newSV(1);
                scalar = sv_setref_iv(scalar, name, 1);
            }
            else {
#ifdef PERL_HAVE_BOOLEANS
                scalar = newSVsv(&PL_sv_yes);
#else
                scalar = &PL_sv_yes;
#endif
            }
            if (anchor)
                hv_store(loader->anchors, anchor, strlen(anchor), SvREFCNT_inc(scalar), 0);
            return scalar;
        }
        else if (strEQ(string, "false")) {
            if (loader->load_bool_jsonpp) {
                char *name = "JSON::PP::Boolean";
                scalar = newSV(1);
                scalar = sv_setref_iv(scalar, name, 0);
            }
            else if (loader->load_bool_boolean) {
                char *name = "boolean";
                scalar = newSV(1);
                scalar = sv_setref_iv(scalar, name, 0);
            }
            else {
#ifdef PERL_HAVE_BOOLEANS
                scalar = newSVsv(&PL_sv_no);
#else
                scalar = &PL_sv_no;
#endif
            }
            if (anchor)
                hv_store(loader->anchors, anchor, strlen(anchor), SvREFCNT_inc(scalar), 0);
            return scalar;
        }
    }

    scalar = newSVpvn(string, length);

    if (style == YAML_PLAIN_SCALAR_STYLE && looks_like_number(scalar) ) {
        /* numify */
        SvIV_please(scalar);
    }

    (void)sv_utf8_decode(scalar);
    if (anchor)
        hv_store(loader->anchors, anchor, strlen(anchor), SvREFCNT_inc(scalar), 0);
    return scalar;
}

/* Load a scalar marked as a regexp as a Perl regular expression.
 * This operation is less common and is tricky, so doing it in Perl code for
 * now.
 */
SV *
load_regexp(perl_yaml_loader_t * loader)
{
    dSP;
    char *string = (char *)loader->event.data.scalar.value;
    STRLEN length = (STRLEN)loader->event.data.scalar.length;
    char *anchor = (char *)loader->event.data.scalar.anchor;
    char *tag = (char *)loader->event.data.scalar.tag;
    char *prefix = TAG_PERL_PREFIX "regexp:";

    SV *regexp = newSVpvn(string, length);
    SvUTF8_on(regexp);

    ENTER;
    SAVETMPS;
    PUSHMARK(sp);
    XPUSHs(regexp);
    PUTBACK;
    call_pv("YAML::XS::__qr_loader", G_SCALAR);
    SPAGAIN;
    regexp = newSVsv(POPs);

    PUTBACK;
    FREETMPS;
    LEAVE;

    if (strlen(tag) > strlen(prefix) && strnEQ(tag, prefix, strlen(prefix))) {
        if (loader->load_blessed) {
            char *class = tag + strlen(prefix);
            sv_bless(regexp, gv_stashpv(class, TRUE));
        }
    }

    if (anchor)
        hv_store(loader->anchors, anchor, strlen(anchor), SvREFCNT_inc(regexp), 0);
    return regexp;
}

/* Load a scalar marked as code as a Perl code reference.
 * This operation is less common and is tricky, so doing it in Perl code for
 * now.
 */
SV*
load_code(perl_yaml_loader_t * loader)
{
    dSP;
    char *string = (char *)loader->event.data.scalar.value;
    STRLEN length = (STRLEN)loader->event.data.scalar.length;
    char *anchor = (char *)loader->event.data.scalar.anchor;
    char *tag = (char *)loader->event.data.scalar.tag;
    char *prefix = TAG_PERL_PREFIX "code:";

    if (! loader->load_code) {
        string = "{}";
        length = 2;
    }
    SV *code = newSVpvn(string, length);
    SvUTF8_on(code);


    ENTER;
    SAVETMPS;
    PUSHMARK(sp);
    XPUSHs(code);
    PUTBACK;
    call_pv("YAML::XS::__code_loader", G_SCALAR);
    SPAGAIN;
    code = newSVsv(POPs);

    PUTBACK;
    FREETMPS;
    LEAVE;

    if (strlen(tag) > strlen(prefix) && strnEQ(tag, prefix, strlen(prefix))) {
        if (loader->load_blessed) {
            char *class = tag + strlen(prefix);
            sv_bless(code, gv_stashpv(class, TRUE));
        }
    }

    if (anchor)
        hv_store(loader->anchors, anchor, strlen(anchor), SvREFCNT_inc(code), 0);
    return code;
}


/*
 * Load a reference to a previously loaded node.
 */
SV *
load_alias(perl_yaml_loader_t *loader)
{
    char *anchor = (char *)loader->event.data.alias.anchor;
    SV **entry = hv_fetch(loader->anchors, anchor, strlen(anchor), 0);
    if (entry)
        return SvREFCNT_inc(*entry);
    croak("%sNo anchor for alias '%s'", ERRMSG, anchor);
}

/*
 * Load a Perl hard reference.
 */
SV *
load_scalar_ref(perl_yaml_loader_t *loader)
{
    SV *value_node;
    char *anchor = (char *)loader->event.data.mapping_start.anchor;
    SV *rv = newRV_noinc(&PL_sv_undef);
    if (anchor)
        hv_store(loader->anchors, anchor, strlen(anchor), SvREFCNT_inc(rv), 0);
    load_node(loader);  /* Load the single hash key (=) */
    value_node = load_node(loader);
    SvRV(rv) = value_node;
    if (load_node(loader))
        croak("%sExpected end of node", ERRMSG);
    return rv;
}

/*
 * Load a Perl typeglob.
 */
SV *
load_glob(perl_yaml_loader_t *loader)
{
    /* XXX Call back a Perl sub to do something interesting here */
    return load_mapping(loader, TAG_PERL_PREFIX "hash");
}

/* -------------------------------------------------------------------------- */

/*
 * Set dumper options from global variables.
 */
void
set_dumper_options(perl_yaml_dumper_t *dumper)
{
    GV *gv;
    char* boolean = "";
    dumper->dump_code = (
        ((gv = gv_fetchpv("YAML::XS::UseCode", TRUE, SVt_PV)) &&
        SvTRUE(GvSV(gv)))
    ||
        ((gv = gv_fetchpv("YAML::XS::DumpCode", TRUE, SVt_PV)) &&
        SvTRUE(GvSV(gv)))
    );

    dumper->quote_number_strings = (
        ((gv = gv_fetchpv("YAML::XS::QuoteNumericStrings", TRUE, SVt_PV)) &&
        SvTRUE(GvSV(gv)))
    );

    gv = gv_fetchpv("YAML::XS::Boolean", FALSE, SVt_PV);
    dumper->dump_bool_jsonpp = 0;
    dumper->dump_bool_boolean = 0;
    if (SvTRUE(GvSV(gv))) {
        boolean = SvPV_nolen(GvSV(gv));
        if (strEQ(boolean, "JSON::PP")) {
            dumper->dump_bool_jsonpp = 1;
            load_module(PERL_LOADMOD_NOIMPORT, newSVpv("JSON::PP", 0), Nullsv);
        }
        else if (strEQ(boolean, "boolean")) {
            dumper->dump_bool_boolean = 1;
            load_module(PERL_LOADMOD_NOIMPORT, newSVpv("boolean", 0), Nullsv);
        }
        else {
            croak("%s",
                "$YAML::XS::Boolean only accepts 'JSON::PP', 'boolean' or a false value");
        }
    }

    /* dumper->emitter.open_ended = 1;
     */
}

/*
 * This is the main Dump function.
 * Take zero or more Perl objects and return a YAML stream (as a string)
 */
void
Dump(SV *dummy, ...)
{
    dXSARGS;
    perl_yaml_dumper_t dumper;
    yaml_event_t event_stream_start;
    yaml_event_t event_stream_end;
    int i;
    SV *yaml = sv_2mortal(newSVpvn("", 0));
    sp = mark;

    set_dumper_options(&dumper);

    /* Set up the emitter object and begin emitting */
    yaml_emitter_initialize(&dumper.emitter);

    /* set indent */
    SV* indent = get_sv("YAML::XS::Indent", GV_ADD);
    if (SvIOK(indent)) yaml_emitter_set_indent(&dumper.emitter, SvIV(indent));

    yaml_emitter_set_unicode(&dumper.emitter, 1);
    yaml_emitter_set_width(&dumper.emitter, 2);
    yaml_emitter_set_output(
        &dumper.emitter,
        &append_output,
        (void *) yaml
    );
    yaml_stream_start_event_initialize(
        &event_stream_start,
        YAML_UTF8_ENCODING
    );
    yaml_emitter_emit(&dumper.emitter, &event_stream_start);

    dumper.anchors = newHV();
    dumper.shadows = newHV();

    sv_2mortal((SV *)dumper.anchors);
    sv_2mortal((SV *)dumper.shadows);

    for (i = 0; i < items; i++) {
        dumper.anchor = 0;

        dump_prewalk(&dumper, ST(i));
        dump_document(&dumper, ST(i));

        hv_clear(dumper.anchors);
        hv_clear(dumper.shadows);
    }

    /* End emitting and destroy the emitter object */
    yaml_stream_end_event_initialize(&event_stream_end);
    yaml_emitter_emit(&dumper.emitter, &event_stream_end);
    yaml_emitter_delete(&dumper.emitter);

    /* Put the YAML stream scalar on the XS output stack */
    if (yaml) {
        SvUTF8_off(yaml);
        XPUSHs(yaml);
    }
    PUTBACK;
}

/*
 * In order to know which nodes will need anchors (for later aliasing) it is
 * necessary to walk the entire data structure first. Once a node has been
 * seen twice you can stop walking it. That way we can handle circular refs.
 * All the node information is stored in an HV.
 */
void
dump_prewalk(perl_yaml_dumper_t *dumper, SV *node)
{
    int i, len;
    U32 ref_type;
    SvGETMAGIC(node);

    if (! (SvROK(node) || SvTYPE(node) == SVt_PVGV)) return;

    {
        SV *object = SvROK(node) ? SvRV(node) : node;
        SV **seen =
            hv_fetch(dumper->anchors, (char *)&object, sizeof(object), 0);
        if (seen) {
            if (*seen == &PL_sv_undef) {
                hv_store(
                    dumper->anchors, (char *)&object, sizeof(object),
                    &PL_sv_yes, 0
                );
            }
            return;
        }
        hv_store(
            dumper->anchors, (char *)&object, sizeof(object), &PL_sv_undef, 0
        );
    }

    if (SvTYPE(node) == SVt_PVGV) {
        node = dump_glob(dumper, node);
    }

    ref_type = SvTYPE(SvRV(node));
    if (ref_type == SVt_PVAV) {
        AV *array = (AV *)SvRV(node);
        int array_size = av_len(array) + 1;
        for (i = 0; i < array_size; i++) {
            SV **entry = av_fetch(array, i, 0);
            if (entry)
                dump_prewalk(dumper, *entry);
        }
    }
    else if (ref_type == SVt_PVHV) {
        HV *hash = (HV *)SvRV(node);
        HE *he;
        SV *key;
        SV *val;
        hv_iterinit(hash);

        while ((he = hv_iternext(hash))) {
            key = hv_iterkeysv(he);
            he = hv_fetch_ent(hash, key, 0, 0);
            val = he ? HeVAL(he) : NULL;
            if (val) {
                dump_prewalk(dumper, val);
            }
        }
    }
    else if (ref_type <= SVt_PVNV || ref_type == SVt_PVGV) {
        SV *scalar = SvRV(node);
        dump_prewalk(dumper, scalar);
    }
}

void
dump_document(perl_yaml_dumper_t *dumper, SV *node)
{
    yaml_event_t event_document_start;
    yaml_event_t event_document_end;
    yaml_document_start_event_initialize(
        &event_document_start, NULL, NULL, NULL, 0
    );
    yaml_emitter_emit(&dumper->emitter, &event_document_start);
    dump_node(dumper, node);
    yaml_document_end_event_initialize(&event_document_end, 1);
    yaml_emitter_emit(&dumper->emitter, &event_document_end);
}

void
dump_node(perl_yaml_dumper_t *dumper, SV *node)
{
    yaml_char_t *anchor = NULL;
    yaml_char_t *tag = NULL;
    const char *class = NULL;

    SvGETMAGIC(node);
    if (SvTYPE(node) == SVt_PVGV) {
        SV **svr;
        tag = (yaml_char_t *)TAG_PERL_PREFIX "glob";
        anchor = get_yaml_anchor(dumper, node);
        if (anchor && strEQ((char *)anchor, "")) return;
        svr = hv_fetch(dumper->shadows, (char *)&node, sizeof(node), 0);
        if (svr) {
            node = SvREFCNT_inc(*svr);
        }
    }

    if (SvROK(node)) {
        SV *rnode = SvRV(node);
        U32 ref_type = SvTYPE(rnode);
        if (ref_type == SVt_PVHV)
            dump_hash(dumper, node, anchor, tag);
        else if (ref_type == SVt_PVAV)
            dump_array(dumper, node);
        else if (ref_type <= SVt_PVNV || ref_type == SVt_PVGV)
            dump_ref(dumper, node);
        else if (ref_type == SVt_PVCV)
            dump_code(dumper, node);
        else if (ref_type == SVt_PVMG) {
            MAGIC *mg;
            yaml_char_t *tag = NULL;
            if (SvMAGICAL(rnode)) {
                if ((mg = mg_find(rnode, PERL_MAGIC_qr))) {
                    tag = (yaml_char_t *)form(TAG_PERL_PREFIX "regexp");
                    class = sv_reftype(rnode, TRUE);
                    if (!strEQ(class, "Regexp"))
                        tag = (yaml_char_t *)form("%s:%s", tag, class);
                }
                dump_scalar(dumper, node, tag);
            }
            else {
                class = sv_reftype(rnode, TRUE);
                if (
                        dumper->dump_bool_jsonpp
                        && strEQ(class, "JSON::PP::Boolean")
                    ||
                        dumper->dump_bool_boolean
                        && strEQ(class, "boolean")
                    ) {
                    if (SvIV(node)) {
                        dump_scalar(dumper, &PL_sv_yes, NULL);
                    }
                    else {
                        dump_scalar(dumper, &PL_sv_no, NULL);
                    }
                }
                else {
                    tag = (yaml_char_t *)form(
                        TAG_PERL_PREFIX "scalar:%s",
                        class
                    );
                    node = rnode;
                    dump_scalar(dumper, node, tag);
                }
            }
        }
#if PERL_REVISION > 5 || (PERL_REVISION == 5 && PERL_VERSION >= 11)
        else if (ref_type == SVt_REGEXP) {
            yaml_char_t *tag = (yaml_char_t *)form(TAG_PERL_PREFIX "regexp");
            class = sv_reftype(rnode, TRUE);
                if (!strEQ(class, "Regexp"))
                     tag = (yaml_char_t *)form("%s:%s", tag, class);
            dump_scalar(dumper, node, tag);
        }
#endif
        else {
            printf(
                "YAML::XS dump unhandled ref. type == '%d'!\n",
                (int)ref_type
            );
            dump_scalar(dumper, rnode, NULL);
        }
    }
    else {
        dump_scalar(dumper, node, NULL);
    }
}

yaml_char_t *
get_yaml_anchor(perl_yaml_dumper_t *dumper, SV *node)
{
    yaml_event_t event_alias;
    SV *iv;
    SV **seen = hv_fetch(dumper->anchors, (char *)&node, sizeof(node), 0);
    if (seen && *seen != &PL_sv_undef) {
        if (*seen == &PL_sv_yes) {
            dumper->anchor++;
            iv = newSViv(dumper->anchor);
            hv_store(dumper->anchors, (char *)&node, sizeof(node), iv, 0);
            return (yaml_char_t*)SvPV_nolen(iv);
        }
        else {
            yaml_char_t *anchor = (yaml_char_t *)SvPV_nolen(*seen);
            yaml_alias_event_initialize(&event_alias, anchor);
            yaml_emitter_emit(&dumper->emitter, &event_alias);
            return (yaml_char_t *) "";
        }
    }
    return NULL;
}

yaml_char_t *
get_yaml_tag(SV *node)
{
    yaml_char_t *tag;
    const char *class;
    const char *kind = "";
    if (! (
        sv_isobject(node) ||
        (SvRV(node) && ( SvTYPE(SvRV(node)) == SVt_PVCV))
    )) return NULL;
    class = sv_reftype(SvRV(node), TRUE);

    switch (SvTYPE(SvRV(node))) {
        case SVt_PVAV: { kind = "array"; break; }
        case SVt_PVHV: { kind = "hash"; break; }
        case SVt_PVCV: { kind = "code"; break; }
    }
    if ((strlen(kind) == 0))
        tag = (yaml_char_t *)form("%s%s", TAG_PERL_PREFIX, class);
    else if (SvTYPE(SvRV(node)) == SVt_PVCV && strEQ(class, "CODE"))
        tag = (yaml_char_t *)form("%s%s", TAG_PERL_PREFIX, kind);
    else
        tag = (yaml_char_t *)form("%s%s:%s", TAG_PERL_PREFIX, kind, class);
    return tag;
}

void
dump_hash(
    perl_yaml_dumper_t *dumper, SV *node,
    yaml_char_t *anchor, yaml_char_t *tag)
{
    yaml_event_t event_mapping_start;
    yaml_event_t event_mapping_end;
    int i;
    int len;
    AV *av;
    HV *hash = (HV *)SvRV(node);
    HE *he;

    if (!anchor)
        anchor = get_yaml_anchor(dumper, (SV *)hash);
    if (anchor && strEQ((char*)anchor, "")) return;

    if (!tag)
        tag = get_yaml_tag(node);

    yaml_mapping_start_event_initialize(
        &event_mapping_start, anchor, tag, 0, YAML_BLOCK_MAPPING_STYLE
    );
    yaml_emitter_emit(&dumper->emitter, &event_mapping_start);

    av = newAV();
    len = 0;
    hv_iterinit(hash);
    while ((he = hv_iternext(hash))) {
        SV *key = hv_iterkeysv(he);
        av_store(av, AvFILLp(av)+1, key); /* av_push(), really */
        len++;
    }
    STORE_HASH_SORT;
    for (i = 0; i < len; i++) {
        SV *key = av_shift(av);
        HE *he  = hv_fetch_ent(hash, key, 0, 0);
        SV *val = he ? HeVAL(he) : NULL;
        if (val == NULL) { val = &PL_sv_undef; }
        dump_node(dumper, key);
        dump_node(dumper, val);
    }

    SvREFCNT_dec(av);

    yaml_mapping_end_event_initialize(&event_mapping_end);
    yaml_emitter_emit(&dumper->emitter, &event_mapping_end);
}

void
dump_array(perl_yaml_dumper_t *dumper, SV *node)
{
    yaml_event_t event_sequence_start;
    yaml_event_t event_sequence_end;
    int i;
    yaml_char_t *tag;
    AV *array = (AV *)SvRV(node);
    int array_size = av_len(array) + 1;

    yaml_char_t *anchor = get_yaml_anchor(dumper, (SV *)array);
    if (anchor && strEQ((char *)anchor, "")) return;
    tag = get_yaml_tag(node);

    yaml_sequence_start_event_initialize(
        &event_sequence_start, anchor, tag, 0, YAML_BLOCK_SEQUENCE_STYLE
    );

    yaml_emitter_emit(&dumper->emitter, &event_sequence_start);
    for (i = 0; i < array_size; i++) {
        SV **entry = av_fetch(array, i, 0);
        if (entry == NULL)
            dump_node(dumper, &PL_sv_undef);
        else
            dump_node(dumper, *entry);
    }
    yaml_sequence_end_event_initialize(&event_sequence_end);
    yaml_emitter_emit(&dumper->emitter, &event_sequence_end);
}

void
dump_scalar(perl_yaml_dumper_t *dumper, SV *node, yaml_char_t *tag)
{
    yaml_event_t event_scalar;
    char *string;
    STRLEN string_len;
    int plain_implicit, quoted_implicit;
    yaml_scalar_style_t style = YAML_PLAIN_SCALAR_STYLE;

    if (tag) {
        plain_implicit = quoted_implicit = 0;
    }
    else {
        tag = (yaml_char_t *)TAG_PERL_STR;
        plain_implicit = quoted_implicit = 1;
    }

    SvGETMAGIC(node);
    if (!SvOK(node)) {
        string = "~";
        string_len = 1;
        style = YAML_PLAIN_SCALAR_STYLE;
    }
    else if (node == &PL_sv_yes
#ifdef PERL_HAVE_BOOLEANS
        || (SvIsBOOL(node) && SvTRUE(node))
#endif
    ) {
        string = "true";
        string_len = 4;
        style = YAML_PLAIN_SCALAR_STYLE;
    }
    else if (node == &PL_sv_no
#ifdef PERL_HAVE_BOOLEANS
        || (SvIsBOOL(node) && !SvTRUE(node))
#endif
    ) {
        string = "false";
        string_len = 5;
        style = YAML_PLAIN_SCALAR_STYLE;
    }
    else {
        SV *node_clone = sv_mortalcopy(node);
        string = SvPV_nomg(node_clone, string_len);
        if (
            (string_len == 0) ||
            (string_len == 1 && strEQ(string, "~")) ||
            (string_len == 4 && strEQ(string, "true")) ||
            (string_len == 5 && strEQ(string, "false")) ||
            (string_len == 4 && strEQ(string, "null")) ||
            (SvTYPE(node_clone) >= SVt_PVGV) ||
            ( dumper->quote_number_strings && !SvNIOK(node_clone) && looks_like_number(node_clone) )
        ) {
            style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
        } else {
            if (!SvUTF8(node_clone)) {
            /* copy to new SV and promote to utf8 */
            SV *utf8sv = sv_mortalcopy(node_clone);

            /* get string and length out of utf8 */
            string = SvPVutf8(utf8sv, string_len);
            }
            if(strchr(string, '\n'))
               style = (string_len > 30) ? YAML_LITERAL_SCALAR_STYLE : YAML_DOUBLE_QUOTED_SCALAR_STYLE;
        }
    }
    if (! yaml_scalar_event_initialize(
        &event_scalar,
        NULL,
        tag,
        (unsigned char *) string,
        (int) string_len,
        plain_implicit,
        quoted_implicit,
        style
    )) {
        croak("Could not initialize scalar event\n");
    }
    if (! yaml_emitter_emit(&dumper->emitter, &event_scalar))
        croak("%sEmit scalar '%s', error: %s\n",
            ERRMSG,
            string, dumper->emitter.problem
        );
}

void
dump_code(perl_yaml_dumper_t *dumper, SV *node)
{
    yaml_event_t event_scalar;
    yaml_char_t *tag;
    yaml_scalar_style_t style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
    char *string = "{ \"DUMMY\" }";
    if (dumper->dump_code) {
        /* load_module(PERL_LOADMOD_NOIMPORT, newSVpv("B::Deparse", 0), NULL);
         */
        SV *result;
        SV *code = find_coderef("YAML::XS::coderef2text");
        AV *args = newAV();
        av_push(args, SvREFCNT_inc(node));
        args = (AV *)sv_2mortal((SV *)args);
        result = call_coderef(code, args);
        if (result && result != &PL_sv_undef) {
            string = SvPV_nolen(result);
            style = YAML_LITERAL_SCALAR_STYLE;
        }
    }
    tag = get_yaml_tag(node);

    yaml_scalar_event_initialize(
        &event_scalar,
        NULL,
        tag,
        (unsigned char *)string,
        strlen(string),
        0,
        0,
        style
    );

    yaml_emitter_emit(&dumper->emitter, &event_scalar);
}

SV *
dump_glob(perl_yaml_dumper_t *dumper, SV *node)
{
    SV *result;
    SV *code = find_coderef("YAML::XS::glob2hash");
    AV *args = newAV();
    av_push(args, SvREFCNT_inc(node));
    args = (AV *)sv_2mortal((SV *)args);
    result = call_coderef(code, args);
    hv_store(
        dumper->shadows, (char *)&node, sizeof(node),
        result, 0
    );
    return result;
}

/* XXX Refo this to just dump a special map */
void
dump_ref(perl_yaml_dumper_t *dumper, SV *node)
{
    yaml_event_t event_mapping_start;
    yaml_event_t event_mapping_end;
    yaml_event_t event_scalar;
    SV *referent = SvRV(node);

    yaml_char_t *anchor = get_yaml_anchor(dumper, referent);
    if (anchor && strEQ((char *)anchor, "")) return;

    yaml_mapping_start_event_initialize(
        &event_mapping_start, anchor,
        (unsigned char *)TAG_PERL_PREFIX "ref",
        0, YAML_BLOCK_MAPPING_STYLE
    );
    yaml_emitter_emit(&dumper->emitter, &event_mapping_start);

    yaml_scalar_event_initialize(
        &event_scalar,
        NULL, NULL,
        (unsigned char *)"=", 1,
        1, 1,
        YAML_PLAIN_SCALAR_STYLE
    );
    yaml_emitter_emit(&dumper->emitter, &event_scalar);
    dump_node(dumper, referent);

    yaml_mapping_end_event_initialize(&event_mapping_end);
    yaml_emitter_emit(&dumper->emitter, &event_mapping_end);
}

int
append_output(void *yaml, unsigned char *buffer, size_t size)
{
    sv_catpvn((SV *)yaml, (const char *)buffer, (STRLEN)size);
    return 1;
}

/* XXX Make -Wall not complain about 'local_patches' not being used. */
#if !defined(PERL_PATCHLEVEL_H_IMPLICIT)
void xxx_local_patches() {
    printf("%s", local_patches[0]);
}
#endif

/*
    Object Oriented Interface
*/

int
_match_core_schema(char *string)
{
    int i = 0;
    int got_decimal = 0;
    int got_mantissa = 0;
    int is_float = 0;
    int got_dot = 0;

    if (strEQ(string, "true") || strEQ(string, "TRUE") || strEQ(string, "True")) {
        return YAML_XS_SCALAR_TYPE_BOOL_TRUE;
    }
    if (strEQ(string, "false") || strEQ(string, "FALSE") || strEQ(string, "False")) {
        return YAML_XS_SCALAR_TYPE_BOOL_FALSE;
    }
    if (strEQ(string, "null") || strEQ(string, "NULL") || strEQ(string, "Null") || strEQ(string, "~") || strEQ(string, "")) {
        return YAML_XS_SCALAR_TYPE_NULL;
    }
    if (
        strEQ(string, ".INF") || strEQ(string, ".Inf") || strEQ(string, ".inf")
        || strEQ(string, "+.INF") || strEQ(string, "+.Inf") || strEQ(string, "+.inf")
        || strEQ(string, "-.INF") || strEQ(string, "-.Inf") || strEQ(string, "-.inf")
        ) {
        return YAML_XS_SCALAR_TYPE_FLOAT_INF;
    }
    if (strEQ(string, ".NAN") || strEQ(string, ".NaN") || strEQ(string, ".nan")) {
        return YAML_XS_SCALAR_TYPE_FLOAT_NAN;
    }
    if (string[0] == 48 && string[1] == 111) {
        for (i=2; i < strlen(string); i++) {
            if (!( string[i] >= 48 && string[i] <= 55)) {       // 0-7
                return YAML_XS_SCALAR_TYPE_STRING;
            }
        }
        return YAML_XS_SCALAR_TYPE_INT_OCT;
    }
    if (string[0] == 48 && string[1] == 120) {
        for (i=2; i < strlen(string); i++) {
            if (!(
                   (string[i] >= 48 && string[i] <= 57)    // 0-10
                || (string[i] >= 97 && string[i] <= 102)   // a-f
                || (string[i] >= 65 && string[i] <= 70)    // A-F
                )
            ) {
                return YAML_XS_SCALAR_TYPE_STRING;
            }
        }
        return YAML_XS_SCALAR_TYPE_INT_HEX;
    }

    if (string[0] == 43 || string[0] == 45) { // +-
        i++;
    }
    while (i < strlen(string)) {
        if (string[i] >= 48 && string[i] <= 57) { // 0-9
            got_decimal = 1;
        }
        else if (got_dot == 0 && string[i] == 46) { // .
            is_float = 1;
            got_dot = 1;
            while (i < strlen(string)) {
                if (string[i] >= 48 && string[i] <= 57) { // 0-9
                    got_mantissa = 1;
                }
                else {
                    break;
                }
                i++;
            }
        }
        else {
            break;
        }
        i++;
    }
    if (! got_mantissa && ! got_decimal) {
        return YAML_XS_SCALAR_TYPE_STRING;
    }
    int got_exponent = 0;
    if (i < strlen(string) && (string[i] == 101 || string[i] == 69)) { // eE
        i++;
        is_float = 1;
        if (string[i] == 43 || string[i] == 45) { // +-
            i++;
        }
        while (i < strlen(string)) {
            if (string[i] >= 48 && string[i] <= 57) { // 0-9
                got_exponent = 1;
            }
            else {
                break;
            }
            i++;
        }
        if (! got_exponent) {
            return YAML_XS_SCALAR_TYPE_STRING;
        }
    }
    if (i < strlen(string)) {
        return YAML_XS_SCALAR_TYPE_STRING;
    }
    if (is_float) {
        return YAML_XS_SCALAR_TYPE_FLOAT;
    }
    else {
        return YAML_XS_SCALAR_TYPE_INT;
    }
    return YAML_XS_SCALAR_TYPE_STRING;
}

/*
    LOAD
*/

char *
oo_loader_error_msg(perl_yaml_xs_t *self, char *problem)
{
    char *msg;
    if (!problem)
        problem = (char *)self->parser.problem;
    if (!problem) {
        problem = "A problem";
    }
    else {
        problem = form("The problem:\n\n    %s\n\n", problem);
    }
    msg = form(
        "YAML::XS load Error: "
        "%swas found at document: %d",
        problem,
        self->document
    );
    if (
        self->parser.problem_mark.line ||
        self->parser.problem_mark.column
    )
        msg = form("%s, line: %lu, column: %lu\n",
            msg,
            (unsigned long)self->parser.problem_mark.line + 1,
            (unsigned long)self->parser.problem_mark.column + 1
        );
    else
        msg = form("%s\n", msg);
    if (self->parser.context)
        msg = form("%s%s at line: %lu, column: %lu\n",
            msg,
            self->parser.context,
            (unsigned long)self->parser.context_mark.line + 1,
            (unsigned long)self->parser.context_mark.column + 1
        );

    return msg;
}

void
oo_load_stream(perl_yaml_xs_t *self)
{
    dXSARGS;
    SV *node;
    int has_footer = 0;

    sp = mark;

    self->document = 0;

    self->anchors = newHV();
    sv_2mortal((SV *)self->anchors);

    if (!yaml_parser_parse(&self->parser, &self->event))
        goto load_error;
    if (self->event.type != YAML_STREAM_START_EVENT)
        croak("%sExpected STREAM_START_EVENT; Got: %d != %d",
            ERRMSG,
            self->event.type,
            YAML_STREAM_START_EVENT
         );

    while (1) {
        self->document++;
        if (self->event.type == YAML_DOCUMENT_END_EVENT) {
            has_footer = self->event.data.document_end.implicit ? 0 : 1;
            if (self->require_footer && ! has_footer) {
                croak("load: Document (%d) did not end with '...' (require_footer=1)", self->document-1);
            }
        }
        yaml_event_delete(&self->event);
        if (!yaml_parser_parse(&self->parser, &self->event))
            goto load_error;
        if (self->event.type == YAML_STREAM_END_EVENT)
            break;
        node = oo_load_node(self);
        yaml_event_delete(&self->event);
        hv_clear(self->anchors);

        if (! node) break;

        if (!yaml_parser_parse(&self->parser, &self->event))
            goto load_error;
        if (self->event.type != YAML_DOCUMENT_END_EVENT)
            croak("%sExpected DOCUMENT_END_EVENT", ERRMSG);

        if (! (GIMME_V == G_ARRAY) && self->document > 1) {
        }
        else {
            XPUSHs(sv_2mortal(node));
        }
    }
    if (self->require_footer && ! has_footer) {
        croak("load: Document (%d) did not end with '...' (require_footer=1)", self->document-1);
    }

    if (self->event.type != YAML_STREAM_END_EVENT)
        croak("%sExpected STREAM_END_EVENT; Got: %d != %d",
            ERRMSG,
            self->event.type,
            YAML_STREAM_END_EVENT
         );

    PUTBACK;
    return;

load_error:
    croak("%s", oo_loader_error_msg(self, NULL));
}

SV *
oo_load_node(perl_yaml_xs_t *self)
{
    SV* return_sv = NULL;
    /* This uses stack, but avoids (severe!) memory leaks */
    yaml_event_t uplevel_event;

    uplevel_event = self->event;

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

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

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

    switch (self->event.type) {
        case YAML_MAPPING_START_EVENT:
            return_sv = oo_load_mapping(self);
            break;

        case YAML_SEQUENCE_START_EVENT:
            return_sv = oo_load_sequence(self);
            break;

        case YAML_SCALAR_EVENT:
            return_sv = oo_load_scalar(self);
            break;

        case YAML_ALIAS_EVENT:
            return_sv = oo_load_alias(self);
            break;

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

    yaml_event_delete(&self->event);

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

    return return_sv;

load_error:
    croak("%s", oo_loader_error_msg(self, NULL));
}

SV *
oo_load_sequence(perl_yaml_xs_t *self)
{
    dXCPT;
    SV *node;
    AV *array = newAV();
    SV *array_ref = (SV *)newRV_noinc((SV *)array);
    char *anchor = (char *)self->event.data.sequence_start.anchor;

    XCPT_TRY_START {

        if (anchor)
            hv_store(self->anchors, anchor, strlen(anchor), SvREFCNT_inc(array_ref), 0);

        while ((node = oo_load_node(self))) {
            av_push(array, node);
        }

    } XCPT_TRY_END

    XCPT_CATCH
    {
        SvREFCNT_dec(array_ref);
        XCPT_RETHROW;
    }
    return array_ref;
}

SV *
oo_load_mapping(perl_yaml_xs_t *self)
{
    dXCPT;
    SV *key_node;
    SV *value_node;
    HV *hash = newHV();
    SV *hash_ref = (SV *)newRV_noinc((SV *)hash);
    char *anchor = (char *)self->event.data.mapping_start.anchor;

    XCPT_TRY_START {

        if (anchor)
            hv_store(self->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 = oo_load_node(self))) {
            assert(SvPOK(key_node));
            value_node = oo_load_node(self);
            if ( /* self->forbid_duplicate_keys && */
                hv_exists_ent(hash, key_node, 0)
            ) {
                croak(
                    "%s",
                    oo_loader_error_msg(
                        self,
                        form("Duplicate key '%s'", SvPV_nolen(key_node))
                    )
                );
            }
            hv_store_ent(
                hash, sv_2mortal(key_node), value_node, 0
            );
        }

    } XCPT_TRY_END

    XCPT_CATCH
    {
        SvREFCNT_dec(hash_ref);
        XCPT_RETHROW;
    }
    return hash_ref;
}

SV *
oo_load_scalar(perl_yaml_xs_t *self)
{
    SV *scalar;
    char *string = (char *)self->event.data.scalar.value;
    yaml_scalar_style_t style = self->event.data.scalar.style;
    char *anchor = (char *)self->event.data.scalar.anchor;
    char *tag = (char *)self->event.data.scalar.tag;
    STRLEN length = (STRLEN)self->event.data.scalar.length;
    I32 flags = 0;
    int scalar_type = 0;
    if (tag) {
        if (strEQ(tag, YAML_STR_TAG)) {
            style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
        }
    }

    if (style != YAML_PLAIN_SCALAR_STYLE) {
        goto return_string;
    }

    scalar_type = _match_core_schema(string);

    /* bool true */
    if (scalar_type == YAML_XS_SCALAR_TYPE_BOOL_TRUE) {
#ifdef PERL_HAVE_BOOLEANS
        scalar = newSVsv(&PL_sv_yes);
#else
        scalar = &PL_sv_yes;
#endif
        if (tag && ! strEQ(tag, YAML_BOOL_TAG)) {
            croak("%s", oo_loader_error_msg( self, form("Invalid tag '%s' for value '%s'", tag, string)));
        }
        goto return_scalar;
    }

    /* bool false */
    if (scalar_type == YAML_XS_SCALAR_TYPE_BOOL_FALSE) {
#ifdef PERL_HAVE_BOOLEANS
        scalar = newSVsv(&PL_sv_no);
#else
        scalar = &PL_sv_no;
#endif
        if (tag && ! strEQ(tag, YAML_BOOL_TAG)) {
            croak("%s", oo_loader_error_msg( self, form("Invalid tag '%s' for value '%s'", tag, string)));
        }
        goto return_scalar;
    }

    /* null */
    if (scalar_type == YAML_XS_SCALAR_TYPE_NULL) {
        scalar = newSV(0);
        if (tag && ! strEQ(tag, YAML_NULL_TAG)) {
            croak("%s", oo_loader_error_msg( self, form("Invalid tag '%s' for value '%s'", tag, string)));
        }
        goto return_scalar;
    }

    /* inf */
    if (scalar_type == YAML_XS_SCALAR_TYPE_FLOAT_INF) {
        if (tag && ! strEQ(tag, YAML_FLOAT_TAG)) {
            croak("%s", oo_loader_error_msg( self, form("Invalid tag '%s' for value '%s'", tag, string)));
        }
        if (string[0] == 45) {
            scalar = newSVnv(-NV_INF);
        }
        else {
            scalar = newSVnv(NV_INF);
        }
        goto return_scalar;
    }

    /* nan */
    if (scalar_type == YAML_XS_SCALAR_TYPE_FLOAT_NAN) {
        NV nan = NV_NAN;
        string++;
        length--;
        if (tag && ! strEQ(tag, YAML_FLOAT_TAG)) {
            croak("%s", oo_loader_error_msg( self, form("Invalid tag '%s' for value '%s'", tag, string)));
        }
        scalar = newSVnv(nan);
        goto return_scalar;
    }

    /* oct */
    if (scalar_type == YAML_XS_SCALAR_TYPE_INT_OCT) {
        if (tag && ! strEQ(tag, YAML_INT_TAG)) {
            croak("%s", oo_loader_error_msg( self, form("Invalid tag '%s' for value '%s'", tag, string)));
        }
        string += 2;
        length -= 2;
        int num = grok_oct(string, &length, &flags, NULL);
        scalar = newSViv((int) num);
        goto return_scalar;
    }

    /* hex */
    if (scalar_type == YAML_XS_SCALAR_TYPE_INT_HEX) {
        if (tag && ! strEQ(tag, YAML_INT_TAG)) {
            croak("%s", oo_loader_error_msg( self, form("Invalid tag '%s' for value '%s'", tag, string)));
        }
        string += 2;
        length -= 2;
        int num = grok_hex(string, &length, &flags, NULL);
        scalar = newSViv((int) num);
        goto return_scalar;
    }

    /* float or int */
    if (scalar_type != YAML_XS_SCALAR_TYPE_INT && scalar_type != YAML_XS_SCALAR_TYPE_FLOAT) {
        goto return_string;
    }
    scalar = newSVpvn(string, length);
    if (scalar_type == YAML_XS_SCALAR_TYPE_FLOAT) {
        if (tag && ! strEQ(tag, YAML_FLOAT_TAG)) {
            croak("%s", oo_loader_error_msg( self, form("Invalid tag '%s' for value '%s'", tag, string)));
        }
        SvIV_please(scalar);
        SvNOK_only(scalar);
    }
    else {
        if (tag && ! strEQ(tag, YAML_INT_TAG)) {
            croak("%s", oo_loader_error_msg( self, form("Invalid tag '%s' for value '%s'", tag, string)));
        }
        SvIV_please(scalar);
        SvIOK_only(scalar);
    }
    goto return_scalar;


return_scalar:
    if (anchor) {
        hv_store(self->anchors, anchor, strlen(anchor), SvREFCNT_inc(scalar), 0);
    }
    return scalar;

return_string:
    scalar = newSVpvn(string, length);
    if (tag && ! strEQ(tag, YAML_STR_TAG)) {
        croak("%s", oo_loader_error_msg( self, form("Invalid tag '%s' for value '%s'", tag, string)));
    }
    if (anchor) {
        hv_store(self->anchors, anchor, strlen(anchor), SvREFCNT_inc(scalar), 0);
    }
    (void)sv_utf8_decode(scalar);
    return scalar;


}

SV *
oo_load_alias(perl_yaml_xs_t *self)
{
    char *anchor = (char *)self->event.data.alias.anchor;
    SV **entry = hv_fetch(self->anchors, anchor, strlen(anchor), 0);
    if (entry)
        return SvREFCNT_inc(*entry);
    croak("%s", oo_loader_error_msg(self, form("No anchor for alias '%s'", anchor)));
}

/*
    DUMP
*/

void
oo_dump_stream(perl_yaml_xs_t *self, ...)
{
    dXSARGS;
    int i;
    yaml_event_t event_stream_start;
    yaml_event_t event_stream_end;

    sp = mark;
    yaml_stream_start_event_initialize(
        &event_stream_start,
        YAML_UTF8_ENCODING
    );
    if (!yaml_emitter_emit(&self->emitter, &event_stream_start))
        croak("ERROR: %s", self->emitter.problem);

    self->anchors = newHV();
    sv_2mortal((SV *)self->anchors);

    for (i = 1; i < items; i++) {
        self->anchor = 0;
        oo_dump_prewalk(self, ST(i));
        oo_dump_document(self, ST(i));
        hv_clear(self->anchors);
    }

    yaml_stream_end_event_initialize(&event_stream_end);
    if (!yaml_emitter_emit(&self->emitter, &event_stream_end)) {
        croak("ERROR: %s", self->emitter.problem);
    }

    PUTBACK;
    return;
}

void
oo_dump_document(perl_yaml_xs_t *self, SV *node)
{
    yaml_event_t event_document_start;
    yaml_event_t event_document_end;

    yaml_document_start_event_initialize(
        &event_document_start, NULL, NULL, NULL, self->header ? 0 : 1
    );
    if (!yaml_emitter_emit(&self->emitter, &event_document_start)) {
        croak("ERROR: %s", self->emitter.problem);
    }

    oo_dump_node(self, node);

    yaml_document_end_event_initialize(&event_document_end, self->footer ? 0 : 1);
    yaml_emitter_emit(&self->emitter, &event_document_end);
}

void
oo_dump_node(perl_yaml_xs_t *self, SV *node)
{
    yaml_char_t *anchor = NULL;
    if (SvROK(node)) {
        SV *rnode = SvRV(node);
        U32 ref_type = SvTYPE(rnode);
        if (ref_type == SVt_PVHV)
            oo_dump_hash(self, node, anchor);
        else if (ref_type == SVt_PVAV) {
            oo_dump_array(self, node, anchor);
        }
    }
    else {
        oo_dump_scalar(self, node);
    }
}

void
oo_dump_hash(perl_yaml_xs_t *self, SV *node, yaml_char_t *anchor)
{
    yaml_event_t event_mapping_start;
    yaml_event_t event_mapping_end;
    int i;
    int len;
    AV *av;
    HV *hash = (HV *)SvRV(node);
    HE *he;

    if (!anchor)
        anchor = oo_get_yaml_anchor(self, (SV *)hash);
    if (anchor && strEQ((char*)anchor, "")) return;

    yaml_mapping_start_event_initialize(
        &event_mapping_start, anchor, NULL, 0, YAML_BLOCK_MAPPING_STYLE
    );
    yaml_emitter_emit(&self->emitter, &event_mapping_start);

    av = newAV();
    len = 0;
    hv_iterinit(hash);
    while ((he = hv_iternext(hash))) {
        SV *key = hv_iterkeysv(he);
        av_store(av, AvFILLp(av)+1, key); /* av_push(), really */
        len++;
    }
    STORE_HASH_SORT;
    for (i = 0; i < len; i++) {
        SV *key = av_shift(av);
        HE *he  = hv_fetch_ent(hash, key, 0, 0);
        SV *val = he ? HeVAL(he) : NULL;
        if (val == NULL) { val = &PL_sv_undef; }
        oo_dump_node(self, key);
        oo_dump_node(self, val);
    }

    SvREFCNT_dec(av);

    yaml_mapping_end_event_initialize(&event_mapping_end);
    yaml_emitter_emit(&self->emitter, &event_mapping_end);
}

void
oo_dump_array(perl_yaml_xs_t *self, SV *node, yaml_char_t *anchor)
{
    yaml_event_t event_sequence_start;
    yaml_event_t event_sequence_end;
    int i;
    AV *array = (AV *)SvRV(node);
    int array_size = av_len(array) + 1;

    if (!anchor)
        anchor = oo_get_yaml_anchor(self, (SV *)array);
    if (anchor && strEQ((char*)anchor, "")) return;

    yaml_sequence_start_event_initialize(
        &event_sequence_start, anchor, NULL, 0, YAML_BLOCK_SEQUENCE_STYLE
    );
    yaml_emitter_emit(&self->emitter, &event_sequence_start);

    for (i = 0; i < array_size; i++) {
        SV **entry = av_fetch(array, i, 0);
        if (entry == NULL)
            oo_dump_node(self, &PL_sv_undef);
        else
            oo_dump_node(self, *entry);
    }

    yaml_sequence_end_event_initialize(&event_sequence_end);
    yaml_emitter_emit(&self->emitter, &event_sequence_end);
}

void
oo_dump_scalar(perl_yaml_xs_t *self, SV *node)
{
    yaml_event_t event_scalar;
    char *string;
    STRLEN string_len;
    int plain_implicit, quoted_implicit;
    yaml_scalar_style_t style = YAML_PLAIN_SCALAR_STYLE;
    plain_implicit = quoted_implicit = 1;
    int is_num = 0;
    STRLEN length;
    SV *node_clone;
    int i;

    SvGETMAGIC(node);
    if (!SvOK(node)) {
        string = "null";
        string_len = 4;
        style = YAML_PLAIN_SCALAR_STYLE;
    }
    else if (SvNOK(node)) {
        NV val = SvNV(node);
        if (node == &PL_sv_yes
#ifdef PERL_HAVE_BOOLEANS
        || (SvIsBOOL(node) && SvTRUE(node))
#endif
        ) {
            string = "true";
            string_len = 4;
            style = YAML_PLAIN_SCALAR_STYLE;
        }
        else if (node == &PL_sv_no
#ifdef PERL_HAVE_BOOLEANS
        || (SvIsBOOL(node) && !SvTRUE(node))
#endif
        ) {
            string = "false";
            string_len = 5;
            style = YAML_PLAIN_SCALAR_STYLE;
        }
        else if (isnan(val)) {
            string = ".nan";
            string_len = 4;
            style = YAML_PLAIN_SCALAR_STYLE;
        }
        else if (isinf(val)) {
            if (val == -NV_INF) {
                string = "-.inf";
                string_len = 5;
            }
            else {
                string = ".inf";
                string_len = 4;
            }
            style = YAML_PLAIN_SCALAR_STYLE;
        }
        else {
            string = SvPV_nolen(node);
            int dot = 0;
            for (i=0; i < strlen(string); i++) {
                if (string[i] == 46) {
                    dot = 1;
                    break;
                }
            }
            if (! dot) {
                char *add = ".0";
                strcat(string, add);
            }
            string_len = strlen(string);
        }
    }
    else if (SvIOK(node)) {
        string = SvPV_nolen(node);
        string_len = strlen(string);
    }
    else {
        node_clone = sv_mortalcopy(node);
        string = SvPV_nomg(node_clone, string_len);
        if (_match_core_schema(string)) {
            style = YAML_SINGLE_QUOTED_SCALAR_STYLE;
        }
    }

    if (! yaml_scalar_event_initialize(
        &event_scalar,
        NULL,
        NULL,
        (unsigned char *) string,
        (int) string_len,
        plain_implicit,
        quoted_implicit,
        style
    )) {
        croak("Could not initialize scalar event\n");
    }

    if (! yaml_emitter_emit(&self->emitter, &event_scalar))
        croak("%sEmit scalar '%s', error: %s\n",
            ERRMSG,
            string, self->emitter.problem
        );
}

void
oo_dump_prewalk(perl_yaml_xs_t *self, SV *node)
{
    int i;
    U32 ref_type;
    AV *array;
    SvGETMAGIC(node);

    if (! (SvROK(node) || SvTYPE(node) == SVt_PVGV)) return;

    {
        SV *object = SvROK(node) ? SvRV(node) : node;
        SV **seen =
            hv_fetch(self->anchors, (char *)&object, sizeof(object), 0);
        if (seen) {
            if (*seen == &PL_sv_undef) {
                hv_store(
                    self->anchors, (char *)&object, sizeof(object),
                    &PL_sv_yes, 0
                );
            }
            return;
        }
        hv_store(
            self->anchors, (char *)&object, sizeof(object), &PL_sv_undef, 0
        );
    }

    ref_type = SvTYPE(SvRV(node));
    if (ref_type == SVt_PVAV) {
        array = (AV *)SvRV(node);
        int array_size = av_len(array) + 1;
        for (i = 0; i < array_size; i++) {
            SV **entry = av_fetch(array, i, 0);
            if (entry)
                oo_dump_prewalk(self, *entry);
        }
    }
    else if (ref_type == SVt_PVHV) {
        HV *hash = (HV *)SvRV(node);
        HE *he;
        SV *key;
        SV *val;
        hv_iterinit(hash);

        while ((he = hv_iternext(hash))) {
            key = hv_iterkeysv(he);
            he = hv_fetch_ent(hash, key, 0, 0);
            val = he ? HeVAL(he) : NULL;
            if (val) {
                oo_dump_prewalk(self, val);
            }
        }
    }
    else if (ref_type <= SVt_PVNV || ref_type == SVt_PVGV) {
        SV *scalar = SvRV(node);
        oo_dump_prewalk(self, scalar);
    }
}

yaml_char_t *
oo_get_yaml_anchor(perl_yaml_xs_t *self, SV *node)
{
    yaml_event_t event_alias;
    SV *iv;
    SV **seen = hv_fetch(self->anchors, (char *)&node, sizeof(node), 0);
    char *prefix;
    char *label;

    if (seen && *seen != &PL_sv_undef) {
        if (*seen == &PL_sv_yes) {
            self->anchor++;
            iv = newSViv(self->anchor);
            hv_store(self->anchors, (char *)&node, sizeof(node), iv, 0);

            yaml_char_t *anchor = (yaml_char_t *)SvPV_nolen(*seen);
            prefix = self->anchor_prefix;
            label = malloc(strlen(prefix)+strlen((char *)anchor)+1);
            strcpy(label, prefix);
            strcat(label, (char *)anchor);
            return (yaml_char_t *)label;
        }
        else {
            yaml_char_t *anchor = (yaml_char_t *)SvPV_nolen(*seen);
            prefix = self->anchor_prefix;
            label = malloc(strlen(prefix)+strlen((char *)anchor)+1);
            strcpy(label, prefix);
            strcat(label, (char *)anchor);

            yaml_alias_event_initialize(&event_alias, (yaml_char_t *)label);
            yaml_emitter_emit(&self->emitter, &event_alias);
            return (yaml_char_t *) "";
        }
    }
    return NULL;
}


Filemanager

Name Type Size Permission Actions
lib Folder 0755
LibYAML.bs File 0 B 0644
LibYAML.c File 14.71 KB 0644
LibYAML.o File 305.26 KB 0644
LibYAML.xs File 6.84 KB 0644
License File 1.13 KB 0644
MYMETA.json File 889 B 0644
MYMETA.yml File 543 B 0644
Makefile File 29.59 KB 0644
Makefile.PL File 812 B 0644
api.c File 35.75 KB 0644
api.o File 307.51 KB 0644
config.h File 2.23 KB 0644
dumper.c File 9.83 KB 0644
dumper.o File 95.38 KB 0644
emitter.c File 64.82 KB 0644
emitter.o File 286.77 KB 0644
loader.c File 13.76 KB 0644
loader.o File 110.03 KB 0644
parser.c File 43.98 KB 0644
parser.o File 196.98 KB 0644
perl_libyaml.c File 60.95 KB 0644
perl_libyaml.h File 3.63 KB 0644
perl_libyaml.o File 601.5 KB 0644
pm_to_blib File 0 B 0644
ppport.h File 170.76 KB 0644
ppport_sort.h File 1012 B 0644
reader.c File 16.29 KB 0644
reader.o File 74.75 KB 0644
scanner.c File 96.61 KB 0644
scanner.o File 384.85 KB 0644
test.pl File 97 B 0644
update.sh File 673 B 0755
writer.c File 3.95 KB 0644
writer.o File 50.91 KB 0644
yaml.h File 53.16 KB 0644
yaml_private.h File 29.79 KB 0644