#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #ifdef METHOD #undef METHOD #endif #ifdef ref #undef ref #endif #ifdef list #undef list #endif #ifdef do_open #undef do_open #endif #ifdef do_close #undef do_close #endif #ifdef assert #undef assert #endif #ifdef vform #undef vform #endif #include #include #include #include #include #include #include #include #include int intFromSV(SV *data) { if (!SvOK(data)) return 0; if (!SvIOK(data)) croak("DCOP: Cannot convert to integer"); return SvIV(data); } SV *intToSV(int data, SV * self = 0) { return newSViv(data); } uint uintFromSV(SV *data) { if (!SvOK(data)) return 0; if (!SvIOK(data)) croak("DCOP: Cannot convert to integer"); return SvIV(data); } SV *uintToSV(uint data, SV * self = 0) { return newSViv(data); } bool boolFromSV(SV *data) { if (!SvOK(data)) return false; if (SvIOK(data)) return SvIV(data); if (SvPOK(data)) return QCString(SvPV(data, PL_na)).lower() == "true"; croak("DCOP: Cannot convert to bool"); } SV *boolToSV(bool data, SV *self = 0) { return newSViv(data ? 1 : 0); } QCString QCStringFromSV(SV *data) { if (!SvOK(data)) return QCString(); if (!SvPOK(data)) croak("DCOP: Cannot convert to QCString"); return SvPV(data, PL_na); } SV *QCStringToSV(const QCString &data, SV * self = 0) { return data.isNull() ? &PL_sv_undef : newSVpv(data.data(), 0); } QString QStringFromSV(SV *data) { if (!SvOK(data)) return QString::null; if (!SvPOK(data)) croak("DCOP: Cannot convert to QString"); return SvPV(data, PL_na); } SV *QStringToSV(const QString &data, SV * self = 0) { return data.isNull() ? &PL_sv_undef : newSVpv((char *)data.latin1(), 0); } QCStringList QCStringListFromSV(SV *data) { if (!SvROK(data)) croak("DCOP: Not reference"); if (SvTYPE(SvRV(data)) != SVt_PVAV) croak("DCOP: Not an array reference"); QCStringList result; for (int i = 0; i <= av_len((AV*)SvRV(data)); i++) result.append(QCStringFromSV(av_fetch((AV*)SvRV(data), i, 0)[0])); return result; } SV *QCStringListToSV(const QCStringList &data, SV * self = 0) { AV *result = newAV(); for (QCStringList::ConstIterator i = data.begin(); i != data.end(); i++) av_push(result, QCStringToSV(*i)); return newRV((SV*)result); } QStringList QStringListFromSV(SV *data) { if (!SvROK(data)) croak("DCOP: Not reference"); if (SvTYPE(SvRV(data)) != SVt_PVAV) croak("DCOP: Not an array reference"); QStringList result; for (int i = 0; i <= av_len((AV*)SvRV(data)); i++) result.append(QCStringFromSV(av_fetch((AV*)SvRV(data), i, 0)[0])); return result; } SV *QStringListToSV(const QStringList &data, SV * self = 0) { AV *result = newAV(); for (QStringList::ConstIterator i = data.begin(); i != data.end(); i++) av_push(result, QStringToSV(*i)); return newRV((SV*)result); } QPoint QPointFromSV(SV *data) { if (!SvROK(data)) croak("DCOP: Not reference"); if (SvTYPE(SvRV(data)) != SVt_PVAV) croak("DCOP: Not an array reference"); if (av_len((AV*)SvRV(data)) != 1) croak("DCOP: A QPoint must have exactly 2 components"); SV **pts = av_fetch((AV*)SvRV(data), 0, 0); return QPoint(intFromSV(pts[0]), intFromSV(pts[1])); } SV *QPointToSV(const QPoint &data, SV * self = 0) { SV *pts[2] = { intToSV(data.x()), intToSV(data.y()) }; return newRV((SV*)av_make(2, pts)); } QSize QSizeFromSV(SV *data) { if (!SvROK(data)) croak("DCOP: Not reference"); if (SvTYPE(SvRV(data)) != SVt_PVAV) croak("DCOP: Not an array reference"); if (av_len((AV*)SvRV(data)) != 1) croak("DCOP: A QSize must have exactly 2 components"); SV **ext = av_fetch((AV*)SvRV(data), 0, 0); return QSize(intFromSV(ext[0]), intFromSV(ext[1])); } SV *QSizeToSV(const QSize &data, SV * self = 0) { SV *ext[2] = { intToSV(data.width()), intToSV(data.height()) }; return newRV((SV*)av_make(2, ext)); } QRect QRectFromSV(SV *data) { if (!SvROK(data)) croak("DCOP: Not a reference"); if (SvTYPE(SvRV(data)) != SVt_PVAV) croak("DCOP: Not an array reference"); if (av_len((AV*)SvRV(data)) != 1) croak("DCOP: A QRect must have exactly 4 components"); SV **rc = av_fetch((AV*)SvRV(data), 0, 0); return QRect(intFromSV(rc[0]), intFromSV(rc[1]), intFromSV(rc[2]), intFromSV(rc[3])); } SV *QRectToSV(const QRect &data, SV * self = 0) { SV *rc[4] = { intToSV(data.left()), intToSV(data.top()), intToSV(data.width()), intToSV(data.height()) }; return newRV((SV*)av_make(4, rc)); } KURL KURLFromSV(SV *data) { return KURL(QStringFromSV(data)); } SV *KURLToSV(const KURL &data, SV * self = 0) { return QStringToSV(data.url()); } DCOPRef DCOPRefFromSV(SV *data) { if (!sv_isa(data, "DCOP::Object")) croak("DCOP: Not a DCOP::Object"); SV **app = hv_fetch((HV*)SvRV(data), "APP", 3, 0); SV **obj = hv_fetch((HV*)SvRV(data), "OBJ", 3, 0); return DCOPRef(QCStringFromSV(app[0]), QCStringFromSV(obj[0])); } SV *DCOPRefToSV(const DCOPRef &data, SV * self) { SV *ref = newRV((SV*)newHV()); hv_store((HV*)SvRV(ref), "CLIENT", 6, SvREFCNT_inc(self), 0); hv_store((HV*)SvRV(ref), "APP", 3, QCStringToSV(data.app()), 0); hv_store((HV*)SvRV(ref), "OBJ", 3, QCStringToSV(data.object()), 0); return sv_bless(ref, gv_stashpv("DCOP::Object", 0)); } # // Yes, defines *are* ugly... #define CHECK_ARG(t) \ if ((*it) == #t) \ s << t##FromSV(data[i]); #define CHECK_REPLY(t) \ if (replyType == #t) \ { \ t r; \ s >> r; \ return t##ToSV(r, self); \ } #define DATA(func, argn) mapArgs(func, &ST(argn), items - argn) QByteArray mapArgs(const QCString &func, SV **data, int n) { int p = func.find('('), q = func.find(')'); if (p == -1 || q == -1 || q < p) croak("DCOP: Invalid function signature \"%s\"", func.data()); QStringList types = QStringList::split(',', func.mid(p + 1, q - p - 1)); QByteArray result; QDataStream s(result, IO_WriteOnly); QStringList::ConstIterator it = types.begin(); for (int i = 0; i < n; ++i, ++it) { if (it == types.end()) croak("DCOP: Too many (%d) arguments to function \"%s\"", n, func.data()); CHECK_ARG(int) else CHECK_ARG(uint) else CHECK_ARG(bool) else CHECK_ARG(QCString) else CHECK_ARG(QString) else CHECK_ARG(QCStringList) else CHECK_ARG(QStringList) else CHECK_ARG(QPoint) else CHECK_ARG(QSize) else CHECK_ARG(QRect) else CHECK_ARG(KURL) else CHECK_ARG(DCOPRef) else croak("DCOP: Sorry, passing a %s is not implemented", (*it).latin1()); } if (it != types.end()) croak("DCOP: Too few (%d) arguments to function \"%s\"", n, func.data()); return result; } SV* mapReply(const QCString &replyType, const QByteArray &replyData, SV *self) { if (replyType == "void") return sv_newmortal(); QDataStream s(replyData, IO_ReadOnly); CHECK_REPLY(int) else CHECK_REPLY(uint) else CHECK_REPLY(bool) else CHECK_REPLY(QCString) else CHECK_REPLY(QString) else CHECK_REPLY(QCStringList) else CHECK_REPLY(QStringList) else CHECK_REPLY(QPoint) else CHECK_REPLY(QSize) else CHECK_REPLY(QRect) else CHECK_REPLY(KURL) else CHECK_REPLY(DCOPRef) else croak("Sorry, receiving a %s is not implemented", replyType.data()); } bool isMultiWordType(const QString &type) { return type == "unsigned" || type == "signed" || type == "long"; } QCString canonicalizeSignature(const QCString &sig) { QCString normal = DCOPClient::normalizeFunctionSignature(sig); int p = normal.find('('), q = normal.find(')'); QCString result = normal.left(p + 1); result.remove(0, result.findRev(' ') + 1); QStringList params = QStringList::split(',', normal.mid(p + 1, q - p - 1)); for (QStringList::ConstIterator it = params.begin(); it != params.end(); ++it) { QStringList words = QStringList::split(' ', (*it).simplifyWhiteSpace()); for (QStringList::ConstIterator wi = words.begin(); wi != words.end(); ++wi) if (!isMultiWordType(*wi)) { result += *wi; break; } if (it != params.fromLast()) result += ','; } result += ')'; return result; } MODULE = DCOP PACKAGE = DCOP PROTOTYPES: ENABLE DCOPClient * DCOPClient::new() OUTPUT: RETVAL void DCOPClient::DESTROY() bool DCOPClient::attach() OUTPUT: RETVAL bool DCOPClient::detach() OUTPUT: RETVAL bool DCOPClient::isAttached() OUTPUT: RETVAL #if 0 QCString DCOPClient::registerAs(appId, ...) QCString appId PREINIT: bool addPID = true; CODE: if (items > 3) croak("Usage: DCOP::registerAs(THIS, appId [, addPID])"); if (items == 3) addPID = SvIV(ST(2)); RETVAL = THIS->registerAs(appId, addPID); OUTPUT: RETVAL bool DCOPClient::isRegistered() OUTPUT: RETVAL #endif QCString DCOPClient::appId() OUTPUT: RETVAL bool DCOPClient::send(app, obj, func, ...) QCString app QCString obj QCString func CODE: func = canonicalizeSignature(func); RETVAL = THIS->send(app, obj, func, DATA(func, 4)); OUTPUT: RETVAL SV* DCOPClient::call(app, obj, func, ...) QCString app QCString obj QCString func PPCODE: func = canonicalizeSignature(func); QCString replyType; QByteArray replyData; bool success; if ((success = THIS->call(app, obj, func, DATA(func, 4), replyType, replyData))) PUSHs(mapReply(replyType, replyData, ST(0))); else PUSHs(&PL_sv_undef); if (GIMME_V == G_ARRAY) PUSHs(success ? &PL_sv_yes : &PL_sv_no); SV* DCOPClient::findObject(app, obj, func, ...) QCString app QCString obj QCString func PPCODE: func = canonicalizeSignature(func); QCString foundApp; QCString foundObj; if (!THIS->findObject(app, obj, func, DATA(func, 4), foundApp, foundObj)) XSRETURN_UNDEF; PUSHs(QCStringToSV(foundApp)); PUSHs(QCStringToSV(foundObj)); void DCOPClient::emitDCOPSignal(obj, signal, ...) QCString obj QCString signal CODE: signal = canonicalizeSignature(signal); THIS->emitDCOPSignal(obj, signal, DATA(signal, 3)); bool DCOPClient::isApplicationRegistered(app) QCString app OUTPUT: RETVAL QCStringList DCOPClient::registeredApplications() OUTPUT: RETVAL QCStringList DCOPClient::remoteObjects(app) QCString app OUTPUT: RETVAL QCStringList DCOPClient::remoteInterfaces(app, obj) QCString app QCString obj OUTPUT: RETVAL QCStringList DCOPClient::remoteFunctions(app, obj) QCString app QCString obj OUTPUT: RETVAL static QCString DCOPClient::normalizeFunctionSignature(sig) QCString sig OUTPUT: RETVAL QCString canonicalizeSignature(sig) QCString sig CODE: RETVAL = canonicalizeSignature(sig); OUTPUT: RETVAL