Chandra

 view release on metacpan or  search on metacpan

xs/app.xs  view on Meta::CPAN

        SPAGAIN;
        if (count > 0 && !SvTRUE(ERRSV)) {
            html_sv = newSVsv(POPs);
        } else {
            /* render not available, stringify */
            if (SvTRUE(ERRSV)) {
                /* Clear error from failed render attempt */
                sv_setsv(ERRSV, &PL_sv_undef);
            }
            html_sv = newSVsv(content);
        }
        PUTBACK;
        FREETMPS; LEAVE;
    } else {
        html_sv = newSVsv(content);
    }

    (void)hv_stores(hv, "_html", html_sv);
    RETVAL = SvREFCNT_inc(self);
}
OUTPUT:
    RETVAL

 # ---- _escape_js (also callable from Perl for tests) ----

SV *
_escape_js(str_sv)
    SV *str_sv
CODE:
{
    const char *src;
    STRLEN src_len;
    char *buf;
    STRLEN i, j;

    src = SvPV(str_sv, src_len);
    /* Worst case: every char needs escaping (2x) */
    Newx(buf, src_len * 2 + 1, char);
    j = 0;
    for (i = 0; i < src_len; i++) {
        switch (src[i]) {
            case '\\': buf[j++] = '\\'; buf[j++] = '\\'; break;
            case '\'': buf[j++] = '\\'; buf[j++] = '\''; break;
            case '\n': buf[j++] = '\\'; buf[j++] = 'n';  break;
            case '\r': buf[j++] = '\\'; buf[j++] = 'r';  break;
            default:   buf[j++] = src[i]; break;
        }
    }
    RETVAL = newSVpvn(buf, j);
    Safefree(buf);
}
OUTPUT:
    RETVAL

 # ---- _match_route($path) - returns ($handler, %params) or () ----

void
_match_route(self, path_sv)
    SV *self
    SV *path_sv
PPCODE:
{
    HV *hv = (HV *)SvRV(self);
    SV **routes_svp = hv_fetchs(hv, "_routes", 0);
    const char *path;
    STRLEN path_len;
    AV *path_parts;
    I32 path_count;

    path = SvPV(path_sv, path_len);

    if (!routes_svp || !SvROK(*routes_svp)) {
        /* No routes - set empty opts and return nothing */
        (void)hv_stores(hv, "_current_route_opts", newRV_noinc((SV *)newHV()));
        XSRETURN(0);
    }

    /* Split path by '/' */
    path_parts = newAV();
    sv_2mortal((SV *)path_parts);
    {
        const char *p = path;
        const char *seg_start = p;
        while (1) {
            if (*p == '/' || *p == '\0') {
                av_push(path_parts, newSVpvn(seg_start, p - seg_start));
                if (*p == '\0') break;
                p++;
                seg_start = p;
            } else {
                p++;
            }
        }
    }
    path_count = av_len(path_parts) + 1;

    {
        AV *routes = (AV *)SvRV(*routes_svp);
        I32 route_len = av_len(routes) + 1;
        I32 ri;

        for (ri = 0; ri < route_len; ri++) {
            SV **entry_svp = av_fetch(routes, ri, 0);
            AV *entry;
            SV **pat_svp, **handler_svp, **opts_svp;
            const char *pattern;
            STRLEN pat_len;
            AV *pat_parts;
            I32 pat_count;
            I32 pi;
            int match;
            HV *params;

            if (!entry_svp || !SvROK(*entry_svp)) continue;
            entry = (AV *)SvRV(*entry_svp);

            pat_svp = av_fetch(entry, 0, 0);
            handler_svp = av_fetch(entry, 1, 0);
            opts_svp = av_fetch(entry, 2, 0);
            if (!pat_svp || !handler_svp) continue;

xs/app.xs  view on Meta::CPAN

        (void)hv_store(hv, cache_key, (I32)strlen(cache_key),
                       SvREFCNT_inc(RETVAL), 0);
    }
}
OUTPUT:
    RETVAL

 # ---- open_window(%args) - create a child window ----

SV *
open_window(self, ...)
    SV *self
CODE:
{
    dSP;
    int count;
    I32 i;

    load_module(PERL_LOADMOD_NOIMPORT,
        newSVpvs("Chandra::Window"), NULL);

    ENTER; SAVETMPS;
    PUSHMARK(SP);
    XPUSHs(sv_2mortal(newSVpvs("Chandra::Window")));
    /* Forward all key-value pairs */
    for (i = 1; i < items; i++) {
        XPUSHs(ST(i));
    }
    /* Add parent => $self */
    XPUSHs(sv_2mortal(newSVpvs("parent")));
    XPUSHs(self);
    PUTBACK;
    count = call_method("new", G_SCALAR);
    SPAGAIN;
    RETVAL = (count > 0) ? newSVsv(POPs) : &PL_sv_undef;
    PUTBACK;
    FREETMPS; LEAVE;

    /* Track child windows in _windows array */
    if (SvOK(RETVAL)) {
        HV *hv = (HV *)SvRV(self);
        SV **arr_svp = hv_fetchs(hv, "_windows", 0);
        AV *arr;
        if (arr_svp && SvROK(*arr_svp)) {
            arr = (AV *)SvRV(*arr_svp);
        } else {
            arr = newAV();
            (void)hv_stores(hv, "_windows", newRV_noinc((SV *)arr));
        }
        av_push(arr, SvREFCNT_inc(RETVAL));
    }
}
OUTPUT:
    RETVAL

 # ---- windows() - return all child windows ----

void
windows(self)
    SV *self
PPCODE:
{
    HV *hv = (HV *)SvRV(self);
    SV **arr_svp = hv_fetchs(hv, "_windows", 0);

    if (arr_svp && SvROK(*arr_svp)) {
        AV *arr = (AV *)SvRV(*arr_svp);
        I32 len = av_len(arr) + 1;
        I32 i;
        for (i = 0; i < len; i++) {
            SV **elem = av_fetch(arr, i, 0);
            if (elem && SvOK(*elem)) {
                XPUSHs(sv_2mortal(newSVsv(*elem)));
            }
        }
    }
}

 # ---- window_by_id($id) - find child window by ID ----

SV *
window_by_id(self, id_sv)
    SV *self
    SV *id_sv
CODE:
{
    HV *hv = (HV *)SvRV(self);
    SV **arr_svp = hv_fetchs(hv, "_windows", 0);
    const char *target_id = SvPV_nolen(id_sv);

    RETVAL = &PL_sv_undef;

    if (arr_svp && SvROK(*arr_svp)) {
        AV *arr = (AV *)SvRV(*arr_svp);
        I32 len = av_len(arr) + 1;
        I32 i;
        for (i = 0; i < len; i++) {
            SV **elem = av_fetch(arr, i, 0);
            if (elem && SvOK(*elem) && SvROK(*elem)) {
                HV *win_hv = (HV *)SvRV(*elem);
                SV **id_svp = hv_fetchs(win_hv, "id", 0);
                if (id_svp && SvOK(*id_svp)) {
                    const char *win_id = SvPV_nolen(*id_svp);
                    if (strcmp(win_id, target_id) == 0) {
                        RETVAL = newSVsv(*elem);
                        break;
                    }
                }
            }
        }
    }
}
OUTPUT:
    RETVAL

 # ---- window_count() - return number of child windows ----

int
window_count(self)
    SV *self
CODE:

xs/app.xs  view on Meta::CPAN

        }
        PUTBACK;
        count = call_method("new", G_SCALAR);
        SPAGAIN;
        splash_obj = (count > 0) ? SvREFCNT_inc(POPs) : &PL_sv_undef;
        PUTBACK;
        FREETMPS; LEAVE;
    }

    if (!SvOK(splash_obj) || !sv_isobject(splash_obj)) {
        RETVAL = &PL_sv_undef;
        goto splash_done;
    }

    /* show() */
    {
        ENTER; SAVETMPS;
        PUSHMARK(SP);
        XPUSHs(splash_obj);
        PUTBACK;
        call_method("show", G_DISCARD);
        FREETMPS; LEAVE;
    }

    /* Call init callback if provided */
    if (init_cb && SvROK(init_cb) && SvTYPE(SvRV(init_cb)) == SVt_PVCV) {
        ENTER; SAVETMPS;
        PUSHMARK(SP);
        XPUSHs(splash_obj);
        PUTBACK;
        call_sv(init_cb, G_DISCARD | G_EVAL);
        SPAGAIN;
        if (SvTRUE(ERRSV)) {
            warn("Chandra::App->splash init callback died: %s",
                 SvPV_nolen(ERRSV));
        }
        FREETMPS; LEAVE;
    }

    /* close() */
    {
        ENTER; SAVETMPS;
        PUSHMARK(SP);
        XPUSHs(splash_obj);
        PUTBACK;
        call_method("close", G_DISCARD);
        FREETMPS; LEAVE;
    }

    RETVAL = splash_obj;
    splash_done: ;
}
OUTPUT:
    RETVAL

void
extend_bridge(self, name, source, ...)
    SV *self
    const char *name
    const char *source
PPCODE:
{
    char **deps = NULL;
    int    dep_count = 0;
    int    i;

    PERL_UNUSED_VAR(self);

    /* parse optional depends => [...] */
    if (items > 3 && (items - 3) % 2 == 0) {
        for (i = 3; i < items; i += 2) {
            const char *key = SvPV_nolen(ST(i));
            if (strcmp(key, "depends") == 0) {
                SV *val = ST(i + 1);
                if (SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVAV) {
                    AV *av = (AV *)SvRV(val);
                    SSize_t alen = av_len(av) + 1;
                    int j;
                    dep_count = (int)alen;
                    if (dep_count > 0) {
                        Newx(deps, dep_count, char *);
                        for (j = 0; j < dep_count; j++) {
                            SV **svp = av_fetch(av, j, 0);
                            deps[j] = savepv(svp ? SvPV_nolen(*svp) : "");
                        }
                    }
                }
            }
        }
    }

    chandra_ext_register(aTHX_ name, source, deps, dep_count);

    if (deps) {
        for (i = 0; i < dep_count; i++)
            Safefree(deps[i]);
        Safefree(deps);
    }

    XSRETURN(1);
}



( run in 0.837 second using v1.01-cache-2.11-cpan-71847e10f99 )