Sponsoring The Perl Toolchain Summit 2025: Help make this important event another success Learn more

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