Chandra

 view release on metacpan or  search on metacpan

include/chandra/chandra_store.h  view on Meta::CPAN

    PUTBACK;
    count = call_method("encode", G_SCALAR | G_EVAL);
    SPAGAIN;
    result = (count > 0 && !SvTRUE(ERRSV))
        ? newSVsv(POPs) : newSVpvs("{}");
    if (SvTRUE(ERRSV)) sv_setpvs(ERRSV, "");
    PUTBACK; FREETMPS; LEAVE;
    return result;
}

/* Returns new HV* on success, NULL on corrupt (emits warn) */
static HV *
chandra_store_decode(pTHX_ SV *json_sv, const char *path)
{
    dSP;
    SV *json = chandra_store_get_json(aTHX);
    int count;
    HV *result = NULL;
    ENTER; SAVETMPS;
    PUSHMARK(SP);
    XPUSHs(json);
    XPUSHs(json_sv);
    PUTBACK;
    count = call_method("decode", G_SCALAR | G_EVAL);
    SPAGAIN;
    if (count > 0 && !SvTRUE(ERRSV)) {
        SV *decoded = POPs;
        if (SvOK(decoded) && SvROK(decoded)
                && SvTYPE(SvRV(decoded)) == SVt_PVHV) {
            result = (HV *)SvRV(decoded);
            SvREFCNT_inc_simple_void((SV *)result);
        }
    }
    if (SvTRUE(ERRSV)) sv_setpvs(ERRSV, "");
    PUTBACK; FREETMPS; LEAVE;
    if (!result)
        warn("Chandra::Store: corrupt store '%s', starting fresh\n",
             path ? path : "unknown");
    return result;
}

/* ============================================================================
 * mkdir -p in C
 * ============================================================================ */

static int
chandra_store_mkdirp(const char *path, int mode)
{
    char tmp[4096];
    char *p;
    size_t len;

#ifdef _WIN32
    /* Use Win32 API to avoid Perl's stat/mkdir macro redefinitions */
    DWORD attr = GetFileAttributesA(path);
    if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
        return 0;
#else
    {
        struct stat st;
        if (stat(path, &st) == 0) return 0;
    }
#endif

    strncpy(tmp, path, sizeof(tmp) - 1);
    tmp[sizeof(tmp) - 1] = '\0';
    len = strlen(tmp);
    if (len > 0 && tmp[len - 1] == '/') tmp[len - 1] = '\0';
#ifdef _WIN32
    /* Also handle backslash separators */
    if (len > 0 && tmp[len - 1] == '\\') tmp[len - 1] = '\0';
#endif

    for (p = tmp + 1; *p; p++) {
#ifdef _WIN32
        if (*p == '/' || *p == '\\') {
#else
        if (*p == '/') {
#endif
            *p = '\0';
#ifdef _WIN32
            {
                DWORD a = GetFileAttributesA(tmp);
                if (a == INVALID_FILE_ATTRIBUTES || !(a & FILE_ATTRIBUTE_DIRECTORY))
                    if (!CreateDirectoryA(tmp, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
                        return -1;
            }
#else
            {
                struct stat st;
                if (stat(tmp, &st) != 0)
                    if (mkdir(tmp, mode) != 0 && errno != EEXIST) return -1;
            }
#endif
            *p =
#ifdef _WIN32
                '\\';
#else
                '/';
#endif
        }
    }
#ifdef _WIN32
    if (!CreateDirectoryA(tmp, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
        return -1;
#else
    if (mkdir(tmp, mode) != 0 && errno != EEXIST) return -1;
#endif
    return 0;
}

/* ============================================================================
 * Dot-notation traversal
 *
 * Splits key on '.', walks HV chain, returns (parent HV, leaf key as mortal SV).
 * create=1: missing intermediate HVs are created.
 * Returns NULL on failure (non-hash intermediate, or absent + !create).
 * On "intermediate is not a hash" sets *not_hash = 1.
 * ============================================================================ */

static HV *
chandra_store_traverse(pTHX_ HV *data, const char *key, STRLEN klen,
                       int create, SV **leaf_sv, int *not_hash)
{
    char *buf;
    char *p, *seg;
    HV *node = data;

    *leaf_sv = NULL;
    if (not_hash) *not_hash = 0;

    Newx(buf, klen + 1, char);
    memcpy(buf, key, klen);
    buf[klen] = '\0';

    p   = buf;
    seg = buf;

    while (*p) {
        if (*p == '.') {
            STRLEN seg_len;
            SV **svp;
            *p = '\0';
            seg_len = (STRLEN)(p - seg);

            svp = hv_fetch(node, seg, (I32)seg_len, 0);
            if (!svp || !SvOK(*svp)) {
                if (!create) { Safefree(buf); return NULL; }
                HV *new_hv = newHV();
                (void)hv_store(node, seg, (I32)seg_len,
                               newRV_noinc((SV *)new_hv), 0);



( run in 0.560 second using v1.01-cache-2.11-cpan-39bf76dae61 )