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