#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "PerlGtkInt.h"
#include "ppport.h"
#include "MiscTypes.h"
#include "Derived.h"
void
CroakOpts(
char
* name,
char
* value,
struct
opts * o)
{
dTHR;
SV * result = sv_newmortal();
int
i;
sv_catpv(result,
"invalid "
);
sv_catpv(result, name);
sv_catpv(result,
" "
);
sv_catpv(result, value);
sv_catpv(result,
", expecting"
);
for
(i=0;o[i].name;i++) {
if
(i==0)
sv_catpv(result,
" '"
);
else
if
(o[i+1].name)
sv_catpv(result,
"', '"
);
else
sv_catpv(result,
"', or '"
);
sv_catpv(result, o[i].name);
}
sv_catpv(result,
"'"
);
croak(SvPV(result, PL_na));
}
void
CroakOptsHash(
char
* name,
char
* value, HV * o)
{
dTHR;
SV * result = sv_newmortal();
HE * he;
int
i=0;
sv_catpv(result,
"invalid "
);
sv_catpv(result, name);
sv_catpv(result,
" "
);
sv_catpv(result, value);
sv_catpv(result,
", expecting"
);
hv_iterinit(o);
he = hv_iternext(o);
while
(he) {
I32 len;
char
* key = hv_iterkey(he, &len);
he = hv_iternext(o);
if
(i==0)
sv_catpv(result,
" '"
);
else
if
(he)
sv_catpv(result,
"', '"
);
else
sv_catpv(result,
"', or '"
);
i=1;
sv_catpvn(result, key, len);
}
sv_catpv(result,
"'"
);
croak(SvPV(result, PL_na));
}
long
SvOpt(SV * name,
char
* optname,
struct
opts * o)
{
dTHR;
int
i;
char
* n = SvPV(name, PL_na);
for
(i=0;o[i].name;i++)
if
(strEQ(o[i].name, n))
return
o[i].value;
CroakOpts(optname, n, o);
return
0;
}
SV * newSVOpt(
long
value,
char
* optname,
struct
opts * o)
{
int
i;
for
(i=0;o[i].name;i++)
if
(o[i].value == value)
return
newSVpv(o[i].name, 0);
croak(
"invalid %s value %d"
, optname, value);
return
NULL;
}
SV * newSVMiscRef(
void
* object,
char
* classname,
int
* newref)
{
HV * previous;
SV * result;
if
(!object)
return
newSVsv(&PL_sv_undef);
previous = RetrieveMisc(object);
if
(previous) {
result = newRV((SV*)previous);
if
(newref)
*newref = 0;
}
else
{
HV * h = newHV();
hv_store(h,
"_gtk"
, 4, newSViv((
long
)object), 0);
result = newRV((SV*)h);
RegisterMisc(h, object);
sv_bless(result, gv_stashpv(classname, FALSE));
SvREFCNT_dec(h);
if
(newref)
*newref = 1;
}
return
result;
}
long
SvOptsHash(SV * name,
char
* optname, HV * o)
{
int
i;
STRLEN len;
char
* n = SvPV(name, len);
SV ** s;
if
(*n ==
'-'
) {
n++;
len--;
}
s = hv_fetch(o, n, len, 0);
if
(s)
return
SvIV(*s);
CroakOptsHash(optname, n, o);
return
0;
}
SV * newSVOptsHash(
long
value,
char
* optname, HV * o)
{
int
i;
HE * h;
SV * result = 0;
hv_iterinit(o);
while
((h = hv_iternext(o))) {
SV * s = hv_iterval(o, h);
if
(SvIV(s) == value) {
I32 len;
char
* p = hv_iterkey(h, &len);
result = newSVpv(p, len);
}
}
if
(result)
return
result;
croak(
"invalid %s value %d"
, optname, value);
}
long
SvFlagsHash(SV * name,
char
* optname, HV * o)
{
int
i;
int
val=0;
if
(!name || !SvOK(name))
return
0;
if
(SvRV(name) && (SvTYPE(SvRV(name)) == SVt_PVAV)) {
AV * r = (AV*)SvRV(name);
for
(i=0;i<=av_len(r);i++)
val |= SvOptsHash(*av_fetch(r, i, 0), optname, o);
}
else
if
(SvRV(name) && (SvTYPE(SvRV(name)) == SVt_PVHV)) {
HV * r = (HV*)SvRV(name);
HE * h;
hv_iterinit(r);
while
((h = hv_iternext(r))) {
I32 len;
char
* key = hv_iterkey(h, &len);
SV ** f;
if
(*key ==
'-'
) {
key++;
len--;
}
f = hv_fetch(o, key, len, 0);
if
(f)
val |= SvIV(hv_iterval(o, h));
else
CroakOptsHash(optname, key, o);
}
}
else
val |= SvOptsHash(name, optname, o);
return
val;
}
SV * newSVFlagsHash(
long
value,
char
* optname, HV * o)
{
SV * target, *result;
int
i;
HE * he;
SV * s;
I32 len;
char
* key;
if
(!pgtk_use_array)
target = (SV*)newHV();
else
target = (SV*)newAV();
hv_iterinit(o);
while
((s = hv_iternextsv(o, &key, &len))) {
int
val = SvIV(s);
if
((value & val) == val) {
if
(!pgtk_use_array)
hv_store((HV*)target, key, len, newSViv(1), 0);
else
av_push((AV*)target, newSVpv(key, len));
value &= ~val;
}
}
result = newRV(target);
SvREFCNT_dec(target);
return
result;
}
long
SvOptFlags(SV * name,
char
* optname,
struct
opts * o)
{
int
i;
int
val=0;
if
(!name || !SvOK(name))
return
0;
if
(SvRV(name) && (SvTYPE(SvRV(name)) == SVt_PVAV)) {
AV * r = (AV*)SvRV(name);
for
(i=0;i<=av_len(r);i++)
val |= SvOpt(*av_fetch(r, i, 0), optname, o);
}
else
if
(SvRV(name) && (SvTYPE(SvRV(name)) == SVt_PVHV)) {
HV * r = (HV*)SvRV(name);
for
(i=0;o[i].name;i++) {
SV ** s = hv_fetch(r, o[i].name,
strlen
(o[i].name), 0);
if
(s && SvOK(*s) && SvTRUE(*s))
val |= o[i].value;
}
}
else
val |= SvOpt(name, optname, o);
return
val;
}
SV * newSVOptFlags(
long
value,
char
* optname,
struct
opts * o)
{
SV * result;
if
(!pgtk_use_array) {
HV * h = newHV();
int
i;
result = newRV((SV*)h);
SvREFCNT_dec(h);
for
(i=0;o[i].name;i++)
if
((value & o[i].value) == o[i].value) {
hv_store(h, o[i].name,
strlen
(o[i].name), newSViv(1), 0);
value &= ~o[i].value;
}
}
else
{
AV * a = newAV();
int
i;
result = newRV((SV*)a);
SvREFCNT_dec(a);
for
(i=0;o[i].name;i++)
if
((value & o[i].value) == o[i].value) {
av_push(a, newSVpv(o[i].name, 0));
value &= ~o[i].value;
}
}
return
result;
}
SV * newSVDefEnumHash (GtkType type,
long
value) {
GtkEnumValue * vals;
SV * result;
vals = gtk_type_enum_get_values(type);
if
(!vals) {
warn(
"Invalid type for enum: %s"
, gtk_type_name(type));
return
newSViv(value);
}
while
(vals && vals->value_nick) {
if
(vals->value == value) {
result = newSVpv(vals->value_nick, 0);
if
(!pgtk_use_minus) {
char
*s = SvPV(result, PL_na);
while
(*s) {
if
(*s ==
'-'
) *s =
'_'
;
s++;
}
}
return
result;
}
vals++;
}
return
newSVsv(&PL_sv_undef);
}
SV * newSVDefFlagsHash (GtkType type,
long
value) {
GtkFlagValue * vals;
SV * result;
char
*s, *p;
vals = gtk_type_flags_get_values(type);
if
(!vals) {
warn(
"Invalid type for flags: %s"
, gtk_type_name(type));
return
newSViv(value);
}
if
(!pgtk_use_array) {
HV * h = newHV();
result = newRV((SV*)h);
SvREFCNT_dec(h);
while
(vals && vals->value_nick) {
if
((value & vals->value) == vals->value) {
if
(pgtk_use_minus)
hv_store(h, vals->value_nick,
strlen
(vals->value_nick), newSViv(1), 0);
else
{
p = s = g_strdup(vals->value_nick);
while
(*s) {
if
(*s ==
'-'
) *s =
'_'
;
s++;
}
hv_store(h, p,
strlen
(p), newSViv(1), 0);
g_free(p);
}
value &= ~vals->value;
}
vals++;
}
}
else
{
AV * a = newAV();
result = newRV((SV*)a);
SvREFCNT_dec(a);
while
(vals && vals->value_nick) {
if
((value & vals->value) == vals->value) {
if
(pgtk_use_minus)
av_push(a, newSVpv(vals->value_nick, 0));
else
{
p = s = g_strdup(vals->value_nick);
while
(*s) {
if
(*s ==
'-'
) *s =
'_'
;
s++;
}
av_push(a, newSVpv(p, 0));
g_free(p);
}
value &= ~vals->value;
}
vals++;
}
}
return
result;
}
static
int
hystrEQ(
register
char
* a,
register
char
*b) {
while
(*a && *b) {
if
(*a == *b || ((*a ==
'-'
|| *a ==
'_'
) && (*b ==
'-'
|| *b ==
'_'
))) {
a++;
b++;
}
else
return
0;
}
return
*a == *b;
}
long
SvEFValueLookup (GtkEnumValue * vals,
char
* name, GtkType type) {
GtkEnumValue *v;
dTHR;
if
(!name)
croak(
"Need a value in lookup"
);
if
(*name ==
'-'
)
name++;
v = vals;
while
(v && v->value_nick) {
if
(hystrEQ(name, v->value_nick))
return
v->value;
v++;
}
{
SV * r;
char
* endc=NULL;
long
val;
val =
strtol
(name, &endc, 0);
if
(*name && endc && *endc ==
'\0'
)
return
val;
v = vals;
r = sv_newmortal();
sv_catpv(r,
"invalid "
);
sv_catpv(r, gtk_type_name(type));
sv_catpv(r,
" value "
);
sv_catpv(r, name);
sv_catpv(r,
", expecting: "
);
while
(v && v->value_nick) {
sv_catpv(r, v->value_nick);
if
(++v)
sv_catpv(r,
", "
);
}
croak(SvPV(r, PL_na));
return
0;
}
}
long
SvDefEnumHash (GtkType type, SV *name) {
long
val = 0;
GtkEnumValue * vals;
vals = gtk_type_enum_get_values(type);
if
(!vals) {
warn(
"Invalid type for enum: %s"
, gtk_type_name(type));
return
SvIV(name);
}
return
SvEFValueLookup(vals, SvPV(name, PL_na), type);
}
long
SvDefFlagsHash (GtkType type, SV *name) {
long
val = 0;
GtkFlagValue * vals;
int
i;
vals = gtk_type_flags_get_values(type);
if
(!vals) {
warn(
"Invalid type for flags: %s"
, gtk_type_name(type));
return
SvIV(name);
}
if
(SvROK(name) && (SvTYPE(SvRV(name)) == SVt_PVAV)) {
AV * r = (AV*)SvRV(name);
for
(i=0;i<=av_len(r);i++)
val |= SvEFValueLookup(vals, SvPV(*av_fetch(r, i, 0), PL_na), type);
}
else
if
(SvROK(name) && (SvTYPE(SvRV(name)) == SVt_PVHV)) {
HV * r = (HV*)SvRV(name);
HE * he;
I32 len;
hv_iterinit(r);
while
((he=hv_iternext(r))) {
val |= SvEFValueLookup(vals, hv_iterkey(he, &len), type);
}
}
else
val |= SvEFValueLookup(vals, SvPV(name, PL_na), type);
return
val;
}
void
* SvMiscRef(SV * o,
char
* classname)
{
HV * q;
SV ** s;
if
(!o || !SvOK(o) || !(q=(HV*)SvRV(o)) || (SvTYPE(q) != SVt_PVHV))
return
0;
if
(classname && !PerlGtk_sv_derived_from(o, classname))
croak(
"variable is not of type %s"
, classname);
s = hv_fetch(q,
"_gtk"
, 4, 0);
if
(!s || !SvIV(*s))
croak(
"variable is damaged %s %p -> %p"
, classname, s, s?(
void
*)SvIV(*s):NULL);
return
(
void
*)SvIV(*s);
}
#define USE_GHASH
#ifdef USE_GHASH
static
GHashTable * MiscCache = NULL;
#else
static
HV * MiscCache = 0;
#endif
void
UnregisterMisc(HV * hv_object,
void
* gtk_object)
{
HV * old_hv = NULL;
#ifdef USE_GHASH
if
(!MiscCache)
MiscCache = g_hash_table_new(g_direct_hash, g_direct_equal);
old_hv = g_hash_table_lookup(MiscCache, gtk_object);
g_hash_table_remove(MiscCache, gtk_object);
#else
char
buffer[40];
sprintf
(buffer,
"%lu"
, (unsigned
long
)gtk_object);
if
(!MiscCache)
MiscCache = newHV();
hv_delete(MiscCache, buffer,
strlen
(buffer), G_DISCARD);
#endif
hv_delete(hv_object,
"_gtk"
, 4, G_DISCARD);
}
void
RegisterMisc(HV * hv_object,
void
* gtk_object)
{
#ifdef USE_GHASH
if
(!MiscCache)
MiscCache = g_hash_table_new(g_direct_hash, g_direct_equal);
g_hash_table_insert(MiscCache, gtk_object, hv_object);
#else
char
buffer[40];
sprintf
(buffer,
"%lu"
, (unsigned
long
)gtk_object);
if
(!MiscCache)
MiscCache = newHV();
hv_store(MiscCache, buffer,
strlen
(buffer), newSViv((
long
)hv_object), 0);
#endif
}
HV * RetrieveMisc(
void
* gtk_object)
{
HV * hv_object;
#ifdef USE_GHASH
if
(!MiscCache)
MiscCache = g_hash_table_new(g_direct_hash, g_direct_equal);
hv_object = g_hash_table_lookup(MiscCache, gtk_object);
return
hv_object;
#else
SV ** s;
char
buffer[40];
if
(!MiscCache)
MiscCache = newHV();
sprintf
(buffer,
"%lu"
, (unsigned
long
)gtk_object);
s = hv_fetch(MiscCache, buffer,
strlen
(buffer), 0);
if
(s)
return
(HV*)SvIV(*s);
else
return
0;
#endif
}
void
* pgtk_alloc_temp(
int
size)
{
dTHR;
SV * s = sv_2mortal(newSVpv(
""
,0));
SvGROW(s, size);
memset
(SvPV(s, PL_na), 0, size);
return
SvPV(s, PL_na);
}