#include "mod_perl.h" typedef struct { SV *cv; table *only; } TableDo; #define table_pool(t) ((array_header *)(t))->pool static int Apache_table_do(TableDo *td, const char *key, const char *val) { int count=0, rv=1; dSP; if(td->only && !table_get(td->only, key)) return 1; ENTER;SAVETMPS; PUSHMARK(sp); XPUSHs(sv_2mortal(newSVpv((char *)key,0))); XPUSHs(sv_2mortal(newSVpv((char *)val,0))); PUTBACK; count = perl_call_sv(td->cv, G_SCALAR); SPAGAIN; if(count == 1) rv = POPi; PUTBACK; FREETMPS;LEAVE; return rv; } typedef void ( #ifdef WIN32 _stdcall #endif *TABFUNC) (table *, const char *, const char *); static void table_modify(TiedTable *self, const char *key, SV *sv, TABFUNC tabfunc) { dTHR; const char *val; if(!self->utable) return; if(SvROK(sv) && (SvTYPE(SvRV(sv)) == SVt_PVAV)) { I32 i; AV *av = (AV*)SvRV(sv); for(i=0; i<=AvFILL(av); i++) { val = (const char *)SvPV(*av_fetch(av, i, FALSE),na); (*tabfunc)(self->utable, key, val); } } else { val = (const char *)SvPV(sv,na); (*tabfunc)(self->utable, key, val); } } static void #ifdef WIN32 _stdcall #endif table_delete(table *tab, const char *key, const char *val) { table_unset(tab, val); } static Apache__Table ApacheTable_new(table *utable) { Apache__Table RETVAL = (Apache__Table)safemalloc(sizeof(TiedTable)); RETVAL->utable = utable; RETVAL->ix = 0; RETVAL->elts = NULL; RETVAL->arr = NULL; return RETVAL; } MODULE = Apache::Table PACKAGE = Apache::Table PROTOTYPES: DISABLE BOOT: items = items; /*avoid warning*/ Apache::Table TIEHASH(pclass, table) SV *pclass Apache::table table CODE: if(!pclass) XSRETURN_UNDEF; RETVAL = ApacheTable_new(table); OUTPUT: RETVAL void new(pclass, r, nalloc=10) SV *pclass Apache r int nalloc CODE: if(!pclass) XSRETURN_UNDEF; ST(0) = mod_perl_tie_table(make_table(r->pool, nalloc)); void DESTROY(self) SV *self PREINIT: Apache__Table tab; CODE: tab = (Apache__Table)hvrv2table(self); if(SvROK(self) && SvTYPE(SvRV(self)) == SVt_PVHV) safefree(tab); void FETCH(self, key) Apache::Table self const char *key ALIAS: get = 1 PPCODE: ix = ix; /*avoid warning*/ if(!self->utable) XSRETURN_UNDEF; if(GIMME == G_SCALAR) { const char *val = table_get(self->utable, key); if (val) XPUSHs(sv_2mortal(newSVpv((char*)val,0))); else XSRETURN_UNDEF; } else { int i; array_header *arr = table_elts(self->utable); table_entry *elts = (table_entry *)arr->elts; for (i = 0; i < arr->nelts; ++i) { if (!elts[i].key || strcasecmp(elts[i].key, key)) continue; XPUSHs(sv_2mortal(newSVpv(elts[i].val,0))); } } bool EXISTS(self, key) Apache::Table self const char *key CODE: if(!self->utable) XSRETURN_UNDEF; RETVAL = table_get(self->utable, key) ? TRUE : FALSE; OUTPUT: RETVAL const char* DELETE(self, sv) Apache::Table self SV *sv ALIAS: unset = 1 PREINIT: I32 gimme = GIMME_V; CODE: ix = ix; if(!self->utable) XSRETURN_UNDEF; RETVAL = NULL; if((ix == 0) && (gimme != G_VOID)) { STRLEN n_a; RETVAL = table_get(self->utable, SvPV(sv,n_a)); } table_modify(self, NULL, sv, (TABFUNC)table_delete); if(!RETVAL) XSRETURN_UNDEF; OUTPUT: RETVAL void STORE(self, key, val) Apache::Table self const char *key const char *val ALIAS: set = 1 CODE: ix = ix; /*avoid warning*/ if(!self->utable) XSRETURN_UNDEF; table_set(self->utable, key, val); void CLEAR(self) Apache::Table self ALIAS: clear = 1 CODE: ix = ix; /*avoid warning*/ if(!self->utable) XSRETURN_UNDEF; clear_table(self->utable); const char * NEXTKEY(self, lastkey=Nullsv) Apache::Table self SV *lastkey CODE: if(self->ix >= self->arr->nelts) XSRETURN_UNDEF; RETVAL = self->elts[self->ix++].key; OUTPUT: RETVAL const char * FIRSTKEY(self) Apache::Table self CODE: if(!self->utable) XSRETURN_UNDEF; self->arr = table_elts(self->utable); if(!self->arr->nelts) XSRETURN_UNDEF; self->elts = (table_entry *)self->arr->elts; self->ix = 0; RETVAL = self->elts[self->ix++].key; OUTPUT: RETVAL void add(self, key, sv) Apache::Table self const char *key SV *sv; CODE: table_modify(self, key, sv, (TABFUNC)table_add); void merge(self, key, sv) Apache::Table self const char *key SV *sv CODE: table_modify(self, key, sv, (TABFUNC)table_merge); void do(self, cv, ...) Apache::Table self SV *cv PREINIT: TableDo td; td.only = (table *)NULL; CODE: if(items > 2) { int i; STRLEN len; td.only = make_table(table_pool(self->utable), items-2); for(i=2; ; i++) { char *key = SvPV(ST(i),len); table_set(td.only, key, "1"); if(i == (items - 1)) break; } } td.cv = cv; table_do((int (*) (void *, const char *, const char *)) Apache_table_do, (void *) &td, self->utable, NULL);