#include "perl_xmmsclient.h"
SV *
perl_xmmsclient_new_sv_from_ptr (void *ptr, const char *class) {
SV *obj;
SV *sv;
HV *stash;
obj = (SV *)newHV ();
sv_magic (obj, 0, PERL_MAGIC_ext, (const char *)ptr, 0);
sv = newRV_noinc (obj);
stash = gv_stashpv (class, 0);
sv_bless (sv, stash);
return sv;
}
void *
perl_xmmsclient_get_ptr_from_sv (SV *sv, const char *class) {
MAGIC *mg;
if (!(mg = perl_xmmsclient_get_magic_from_sv (sv, class))) {
return NULL;
}
return (void *)mg->mg_ptr;
}
MAGIC *
perl_xmmsclient_get_magic_from_sv (SV *sv, const char *class) {
MAGIC *mg;
if (!sv || !SvOK (sv) || !SvROK (sv) || !sv_derived_from (sv, class) || !(mg = mg_find (SvRV (sv), PERL_MAGIC_ext))) {
return NULL;
}
return mg;
}
void
_perl_xmmsclient_call_xs (pTHX_ void (*subaddr) (pTHX_ CV *), CV *cv, SV **mark) {
dSP;
PUSHMARK (mark);
(*subaddr) (aTHX_ cv);
PUTBACK;
}
PerlXMMSClientCallback *
perl_xmmsclient_callback_new (SV *func, SV *data, SV *wrapper, int n_params, PerlXMMSClientCallbackParamType param_types[]) {
PerlXMMSClientCallback *cb;
cb = (PerlXMMSClientCallback *)malloc (sizeof (PerlXMMSClientCallback));
memset (cb, '\0', sizeof (PerlXMMSClientCallback));
cb->func = newSVsv (func);
if (data) {
cb->data = newSVsv(data);
}
if (wrapper) {
cb->wrapper = newSVsv(wrapper);
}
cb->n_params = n_params;
if (cb->n_params) {
if (!param_types) {
croak ("n_params is %d but param_types is NULL in perl_xmmsclient_callback_new", n_params);
}
cb->param_types = (PerlXMMSClientCallbackParamType *)malloc (sizeof (PerlXMMSClientCallbackParamType) * n_params);
memcpy (cb->param_types, param_types, n_params * sizeof (PerlXMMSClientCallbackParamType));
}
#ifdef PERL_IMPLICIT_CONTEXT
cb->priv = aTHX;
#endif
return cb;
}
void
perl_xmmsclient_callback_destroy (PerlXMMSClientCallback *cb) {
if (cb) {
if (cb->func) {
SvREFCNT_dec (cb->func);
cb->func = NULL;
}
if (cb->data) {
SvREFCNT_dec (cb->data);
cb->data = NULL;
}
if (cb->param_types) {
free (cb->param_types);
cb->n_params = 0;
cb->param_types = NULL;
}
free (cb);
}
}
void
perl_xmmsclient_callback_invoke (PerlXMMSClientCallback *cb, ...) {
va_list va_args;
dPERL_XMMS_CLIENT_CALLBACK_MARSHAL_SP;
if (cb == NULL) {
croak("cb == NULL in perl_xmmsclient_callback_invoke");
}
PERL_XMMS_CLIENT_MARSHAL_INIT (cb);
ENTER;
SAVETMPS;
PUSHMARK (sp);
va_start (va_args, cb);
if (cb->n_params > 0) {
int i;
for (i = 0; i < cb->n_params; i++) {
SV *sv;
switch (cb->param_types[i]) {
case PERL_XMMSCLIENT_CALLBACK_PARAM_TYPE_CONNECTION:
case PERL_XMMSCLIENT_CALLBACK_PARAM_TYPE_RESULT:
if (!cb->wrapper) {
croak("wrapper == NULL in perl_xmmsclient_callback_invoke");
}
sv = cb->wrapper;
break;
case PERL_XMMSCLIENT_CALLBACK_PARAM_TYPE_FLAG:
sv = newSViv (va_arg (va_args, int));
break;
default:
PUTBACK;
croak ("Unknown PerlXMMSClientCallbackParamType in perl_xmmsclient_callback_invoke");
}
if (!sv) {
PUTBACK;
croak ("failed to convert value to sv");
}
XPUSHs (sv);
}
}
va_end (va_args);
if (cb->data)
XPUSHs (cb->data);
PUTBACK;
call_sv (cb->func, G_DISCARD);
FREETMPS;
LEAVE;
}
char **
perl_xmmsclient_unpack_char_ptr_ptr (SV *arg) {
AV *av;
SV **ssv;
int avlen, i;
char **ret;
if (!SvOK (arg)) {
return NULL;
}
if (SvROK (arg) && (SvTYPE (SvRV (arg)) == SVt_PVAV)) {
av = (AV *)SvRV (arg);
avlen = av_len (av);
ret = (char **)malloc (sizeof (char *) * (avlen + 2));
for (i = 0; i <= avlen; ++i) {
ssv = av_fetch (av, i, 0);
ret[i] = SvPV_nolen (*ssv);
}
ret[avlen + 1] = NULL;
}
else {
croak ("not an array reference");
}
return ret;
}
SV *
perl_xmmsclient_hv_fetch (HV *hv, const char *key, I32 klen) {
SV **val;
val = hv_fetch (hv, key, klen, 0);
if (!val) {
return NULL;
}
return *val;
}
perl_xmmsclient_playlist_t *
perl_xmmsclient_playlist_new (xmmsc_connection_t *conn, const char *playlist) {
perl_xmmsclient_playlist_t *p;
p = (perl_xmmsclient_playlist_t *)malloc (sizeof (perl_xmmsclient_playlist_t));
if (!p) {
croak ("Failed to allocate playlist");
}
xmmsc_ref (conn);
p->conn = conn;
p->name = strdup (playlist);
return p;
}
void
perl_xmmsclient_playlist_destroy (perl_xmmsclient_playlist_t *p) {
if (p->conn) {
xmmsc_unref (p->conn);
p->conn = NULL;
}
if (p->name) {
free (p->name);
}
free (p);
}