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 )