Merge branch 'master' of git.linphone.org:linphone

This commit is contained in:
Jehan Monnier 2013-09-24 16:08:44 +02:00
commit 1b47a0dfd4
14 changed files with 1081 additions and 268 deletions

12
COPYING
View file

@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
@ -225,7 +225,7 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
@ -278,7 +278,7 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest

View file

@ -171,13 +171,15 @@ void linphone_address_destroy(LinphoneAddress *u){
sal_address_unref(u);
}
/**
* Get port number as an integer value.
*/
/**
* Get port number, 0 if not present.
*/
int linphone_address_get_port(const LinphoneAddress *u) {
#ifdef USE_BELLESIP
return sal_address_get_port(u);
#else
return sal_address_get_port_int(u);
#endif
}
/** @} */

View file

@ -190,7 +190,7 @@ EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH = .
INCLUDE_FILE_PATTERNS = *.h
PREDEFINED = DOXYGEN
PREDEFINED = DOXYGEN MS2_PUBLIC= LINPHONE_PUBLIC=
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------

View file

@ -1203,16 +1203,31 @@ void _linphone_call_params_copy(LinphoneCallParams *ncp, const LinphoneCallParam
if (cp->custom_headers) ncp->custom_headers=sal_custom_header_clone(cp->custom_headers);
}
/**
* @ingroup call_control
* Set requested level of privacy for the call.
* \xmlonly <language-tags>javascript</language-tags> \endxmlonly
* @param params the call parameters to be modified
* @param LinphonePrivacy to configure privacy
* */
void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy) {
params->privacy=privacy;
}
/**
* @ingroup call_control
* Get requested level of privacy for the call.
* @param params the call parameters
* @return Privacy mode
* */
LinphonePrivacyMask linphone_call_params_get_privacy(const LinphoneCallParams *params) {
return params->privacy;
}
/**
* @ingroup call_control
* @return string value of LinphonePrivacy enum
**/
const char* linphone_privacy_to_string(LinphonePrivacy privacy) {
switch(privacy) {
case LinphonePrivacyDefault: return "LinphonePrivacyDefault";
@ -1669,7 +1684,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
stream->rtp_addr[0]!='\0' ? stream->rtp_addr : call->resultdesc->addr,
stream->rtp_port,
stream->rtcp_addr[0]!='\0' ? stream->rtcp_addr : call->resultdesc->addr,
linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port) : 0,
linphone_core_rtcp_enabled(lc) ? (stream->rtcp_port ? stream->rtcp_port : stream->rtp_port+1) : 0,
used_pt,
linphone_core_get_audio_jittcomp(lc),
playfile,
@ -1791,7 +1806,8 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
video_stream_set_device_rotation(call->videostream, lc->device_rotation);
video_stream_start(call->videostream,
call->video_profile, rtp_addr, vstream->rtp_port,
rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
rtcp_addr,
linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port ? vstream->rtcp_port : vstream->rtp_port+1) : 0,
used_pt, linphone_core_get_video_jittcomp(lc), cam);
video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
}

View file

@ -4891,26 +4891,58 @@ float linphone_core_get_static_picture_fps(LinphoneCore *lc) {
* @ingroup media_parameters
**/
unsigned long linphone_core_get_native_video_window_id(const LinphoneCore *lc){
if (lc->video_window_id) {
/* case where the video id was previously set by the app*/
return lc->video_window_id;
}else{
#ifdef VIDEO_ENABLED
LinphoneCall *call=linphone_core_get_current_call (lc);
if (call && call->videostream)
return video_stream_get_native_window_id(call->videostream);
if (lc->previewstream)
return video_stream_get_native_window_id(lc->previewstream);
/*case where it was not set but we want to get the one automatically created by mediastreamer2 (desktop versions only)*/
LinphoneCall *call=linphone_core_get_current_call (lc);
if (call && call->videostream)
return video_stream_get_native_window_id(call->videostream);
#endif
return lc->video_window_id;
}
return 0;
}
/**@ingroup media_parameters
/* unsets the video id for all calls (indeed it may be kept by filters or videostream object itself by paused calls)*/
static void unset_video_window_id(LinphoneCore *lc, bool_t preview, unsigned long id){
LinphoneCall *call;
MSList *elem;
if (id!=0 && id!=-1) {
ms_error("Invalid use of unset_video_window_id()");
return;
}
#ifdef VIDEO_ENABLED
for(elem=lc->calls;elem!=NULL;elem=elem->next){
call=(LinphoneCall *) elem->data;
if (call->videostream){
if (preview)
video_stream_set_native_preview_window_id(call->videostream,id);
else
video_stream_set_native_window_id(call->videostream,id);
}
}
#endif
}
/**
* @ingroup media_parameters
* Set the native video window id where the video is to be displayed.
* If not set the core will create its own window.
* For MacOS, Linux, Windows: if not set or zero the core will create its own window, unless the special id -1 is given.
**/
void linphone_core_set_native_video_window_id(LinphoneCore *lc, unsigned long id){
#ifdef VIDEO_ENABLED
LinphoneCall *call=linphone_core_get_current_call(lc);
if (id==0 || id==(unsigned long)-1){
unset_video_window_id(lc,FALSE,id);
}
lc->video_window_id=id;
if (call!=NULL && call->videostream){
video_stream_set_native_window_id(call->videostream,id);
#ifdef VIDEO_ENABLED
{
LinphoneCall *call=linphone_core_get_current_call(lc);
if (call!=NULL && call->videostream){
video_stream_set_native_window_id(call->videostream,id);
}
}
#endif
}
@ -4921,30 +4953,41 @@ void linphone_core_set_native_video_window_id(LinphoneCore *lc, unsigned long id
* @ingroup media_parameters
**/
unsigned long linphone_core_get_native_preview_window_id(const LinphoneCore *lc){
if (lc->preview_window_id){
/*case where the id was set by the app previously*/
return lc->preview_window_id;
}else{
/*case where we want the id automatically created by mediastreamer2 (desktop versions only)*/
#ifdef VIDEO_ENABLED
LinphoneCall *call=linphone_core_get_current_call (lc);
if (call && call->videostream)
return video_stream_get_native_preview_window_id(call->videostream);
if (lc->previewstream)
return video_preview_get_native_window_id(lc->previewstream);
LinphoneCall *call=linphone_core_get_current_call(lc);
if (call && call->videostream)
return video_stream_get_native_preview_window_id(call->videostream);
if (lc->previewstream)
return video_preview_get_native_window_id(lc->previewstream);
#endif
return lc->preview_window_id;
}
return 0;
}
/**
* @ingroup media_parameters
* Set the native window id where the preview video (local camera) is to be displayed.
* This has to be used in conjonction with linphone_core_use_preview_window().
* If not set the core will create its own window.
* MacOS, Linux, Windows: if not set or zero the core will create its own window, unless the special id -1 is given.
**/
void linphone_core_set_native_preview_window_id(LinphoneCore *lc, unsigned long id){
#ifdef VIDEO_ENABLED
LinphoneCall *call=linphone_core_get_current_call(lc);
if (id==0 || id==(unsigned long)-1){
unset_video_window_id(lc,TRUE,id);
}
lc->preview_window_id=id;
if (call!=NULL && call->videostream){
video_stream_set_native_preview_window_id(call->videostream,id);
}else if (lc->previewstream){
video_preview_set_native_window_id(lc->previewstream,id);
#ifdef VIDEO_ENABLED
{
LinphoneCall *call=linphone_core_get_current_call(lc);
if (call!=NULL && call->videostream){
video_stream_set_native_preview_window_id(call->videostream,id);
}else if (lc->previewstream){
video_preview_set_native_window_id(lc->previewstream,id);
}
}
#endif
}

View file

@ -182,9 +182,6 @@ const char *linphone_address_get_scheme(const LinphoneAddress *u);
LINPHONE_PUBLIC const char *linphone_address_get_display_name(const LinphoneAddress* u);
LINPHONE_PUBLIC const char *linphone_address_get_username(const LinphoneAddress *u);
LINPHONE_PUBLIC const char *linphone_address_get_domain(const LinphoneAddress *u);
/**
* Get port number as an integer value, -1 if not set.
*/
LINPHONE_PUBLIC int linphone_address_get_port(const LinphoneAddress *u);
LINPHONE_PUBLIC void linphone_address_set_display_name(LinphoneAddress *u, const char *display_name);
LINPHONE_PUBLIC void linphone_address_set_username(LinphoneAddress *uri, const char *username);
@ -371,24 +368,9 @@ typedef enum _LinphonePrivacy {
* */
typedef unsigned int LinphonePrivacyMask;
/**
* @ingroup call_control
* @return string value of LinphonePrivacy enum
* */
const char* linphone_privacy_to_string(LinphonePrivacy privacy);
/**
* @ingroup call_control
* Set requested level of privacy for the call.
* @param params the call parameters to be modified
* @param LinphonePrivacy to configure privacy
* */
LINPHONE_PUBLIC const char* linphone_privacy_to_string(LinphonePrivacy privacy);
LINPHONE_PUBLIC void linphone_call_params_set_privacy(LinphoneCallParams *params, LinphonePrivacyMask privacy);
/**
* @ingroup call_control
* Get requested level of privacy for the call.
* @param params the call parameters
* @return Privacy mode
* */
LINPHONE_PUBLIC LinphonePrivacyMask linphone_call_params_get_privacy(const LinphoneCallParams *params);
@ -975,9 +957,9 @@ typedef void (*NotifyPresenceReceivedCb)(struct _LinphoneCore *lc, LinphoneFrien
* */
typedef void (*NewSubscribtionRequestCb)(struct _LinphoneCore *lc, LinphoneFriend *lf, const char *url);
/** Callback prototype */
typedef void (*AuthInfoRequested)(struct _LinphoneCore *lc, const char *realm, const char *username);
typedef void (*AuthInfoRequestedCb)(struct _LinphoneCore *lc, const char *realm, const char *username);
/** Callback prototype */
typedef void (*CallLogUpdated)(struct _LinphoneCore *lc, struct _LinphoneCallLog *newcl);
typedef void (*CallLogUpdatedCb)(struct _LinphoneCore *lc, struct _LinphoneCallLog *newcl);
/**
* Callback prototype
* @deprecated use #MessageReceived instead.
@ -987,7 +969,7 @@ typedef void (*CallLogUpdated)(struct _LinphoneCore *lc, struct _LinphoneCallLog
* @param from #LinphoneAddress from
* @param message incoming message
* */
typedef void (*TextMessageReceived)(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message);
typedef void (*TextMessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message);
/**
* Chat message callback prototype
*
@ -995,18 +977,18 @@ typedef void (*TextMessageReceived)(LinphoneCore *lc, LinphoneChatRoom *room, co
* @param room #LinphoneChatRoom involved in this conversation. Can be be created by the framework in case \link #LinphoneAddress the from \endlink is not present in any chat room.
* @param LinphoneChatMessage incoming message
* */
typedef void (*MessageReceived)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message);
typedef void (*MessageReceivedCb)(LinphoneCore *lc, LinphoneChatRoom *room, LinphoneChatMessage *message);
/** Callback prototype */
typedef void (*DtmfReceived)(struct _LinphoneCore* lc, LinphoneCall *call, int dtmf);
typedef void (*DtmfReceivedCb)(struct _LinphoneCore* lc, LinphoneCall *call, int dtmf);
/** Callback prototype */
typedef void (*ReferReceived)(struct _LinphoneCore *lc, const char *refer_to);
typedef void (*ReferReceivedCb)(struct _LinphoneCore *lc, const char *refer_to);
/** Callback prototype */
typedef void (*BuddyInfoUpdated)(struct _LinphoneCore *lc, LinphoneFriend *lf);
typedef void (*BuddyInfoUpdatedCb)(struct _LinphoneCore *lc, LinphoneFriend *lf);
/** Callback prototype for in progress transfers. The new_call_state is the state of the call resulting of the transfer, at the other party. */
typedef void (*LinphoneTransferStateChanged)(struct _LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state);
typedef void (*LinphoneTransferStateChangedCb)(struct _LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state);
/** Callback prototype for receiving quality statistics for calls*/
typedef void (*CallStatsUpdated)(struct _LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats);
typedef void (*CallStatsUpdatedCb)(struct _LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *stats);
/** Callback prototype for receiving info messages*/
typedef void (*LinphoneInfoReceivedCb)(struct _LinphoneCore *lc, LinphoneCall *call, const LinphoneInfoMessage *msg);
@ -1020,15 +1002,15 @@ typedef struct _LinphoneVTable{
LinphoneCallStateCb call_state_changed;/**<Notifies call state changes*/
NotifyPresenceReceivedCb notify_presence_recv; /**< Notify received presence events*/
NewSubscribtionRequestCb new_subscription_request; /**< Notify about pending presence subscription request */
AuthInfoRequested auth_info_requested; /**< Ask the application some authentication information */
CallLogUpdated call_log_updated; /**< Notifies that call log list has been updated */
MessageReceived message_received; /** a message is received, can be text or external body*/
DtmfReceived dtmf_received; /**< A dtmf has been received received */
ReferReceived refer_received; /**< An out of call refer was received */
AuthInfoRequestedCb auth_info_requested; /**< Ask the application some authentication information */
CallLogUpdatedCb call_log_updated; /**< Notifies that call log list has been updated */
MessageReceivedCb message_received; /** a message is received, can be text or external body*/
DtmfReceivedCb dtmf_received; /**< A dtmf has been received received */
ReferReceivedCb refer_received; /**< An out of call refer was received */
CallEncryptionChangedCb call_encryption_changed; /**<Notifies on change in the encryption of call streams */
LinphoneTransferStateChanged transfer_state_changed; /**<Notifies when a transfer is in progress */
BuddyInfoUpdated buddy_info_updated; /**< a LinphoneFriend's BuddyInfo has changed*/
CallStatsUpdated call_stats_updated; /**<Notifies on refreshing of call's statistics. */
LinphoneTransferStateChangedCb transfer_state_changed; /**<Notifies when a transfer is in progress */
BuddyInfoUpdatedCb buddy_info_updated; /**< a LinphoneFriend's BuddyInfo has changed*/
CallStatsUpdatedCb call_stats_updated; /**<Notifies on refreshing of call's statistics. */
LinphoneInfoReceivedCb info_received; /**<Notifies an incoming informational message received.*/
LinphoneSubscriptionStateChangedCb subscription_state_changed; /**<Notifies subscription state change */
LinphoneEventIncomingNotifyCb notify_received; /**< Notifies a an event notification, see linphone_core_subscribe() */
@ -1038,7 +1020,7 @@ typedef struct _LinphoneVTable{
DisplayMessageCb display_warning;/**< @deprecated Callback to display a warning to the user */
DisplayUrlCb display_url; /**< @deprecated */
ShowInterfaceCb show; /**< @deprecated Notifies the application that it should show up*/
TextMessageReceived text_received; /** @deprecated, use #message_received instead <br> A text message has been received */
TextMessageReceivedCb text_received; /** @deprecated, use #message_received instead <br> A text message has been received */
} LinphoneCoreVTable;
/**

View file

@ -2379,9 +2379,11 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(JNIEnv*
jobject oldWindow = (jobject) linphone_core_get_native_video_window_id((LinphoneCore*)lc);
if (obj != NULL) {
obj = env->NewGlobalRef(obj);
}
ms_message("Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(): NewGlobalRef(%p)",obj);
}else ms_message("Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(): setting to NULL");
linphone_core_set_native_video_window_id((LinphoneCore*)lc,(unsigned long)obj);
if (oldWindow != NULL) {
ms_message("Java_org_linphone_core_LinphoneCoreImpl_setVideoWindowId(): DeleteGlobalRef(%p)",oldWindow);
env->DeleteGlobalRef(oldWindow);
}
}
@ -2393,9 +2395,11 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPreviewWindowId(JNIEn
jobject oldWindow = (jobject) linphone_core_get_native_preview_window_id((LinphoneCore*)lc);
if (obj != NULL) {
obj = env->NewGlobalRef(obj);
}
ms_message("Java_org_linphone_core_LinphoneCoreImpl_setPreviewWindowId(): NewGlobalRef(%p)",obj);
}else ms_message("Java_org_linphone_core_LinphoneCoreImpl_setPreviewWindowId(): setting to NULL");
linphone_core_set_native_preview_window_id((LinphoneCore*)lc,(unsigned long)obj);
if (oldWindow != NULL) {
ms_message("Java_org_linphone_core_LinphoneCoreImpl_setPreviewWindowId(): DeleteGlobalRef(%p)",oldWindow);
env->DeleteGlobalRef(oldWindow);
}
}

@ -1 +1 @@
Subproject commit 5b941cb169940ae643de86e957daa86c31c25145
Subproject commit 214f82f8942f9d1c419f038dbd33b36b65e2a1e6

View file

@ -12,7 +12,7 @@ COMMON_CFLAGS=\
$(STRICT_OPTIONS) \
$(LIBXML2_CFLAGS)
AM_CXXFLAGS=$(LIBXML2_CFLAGS)
AM_CXXFLAGS=$(LIBXML2_CFLAGS) $(STRICT_OPTIONS)
EXTRA_DIST=xml2lpc_jni.cc lpc2xml_jni.cc
@ -59,7 +59,9 @@ lpc2xml_test_LDADD=\
$(top_builddir)/coreapi/liblinphone.la \
liblpc2xml.la
lp_gen_wrappers_SOURCES=genwrappers.cc
lp_gen_wrappers_SOURCES=genwrappers.cc \
software-desc.cc software-desc.hh \
generator.cc generator.hh
lp_gen_wrappers_LDADD= \
$(LIBXML2_LIBS)

284
tools/generator.cc Normal file
View file

@ -0,0 +1,284 @@
/*
linphone
Copyright (C) 2013 Belledonne Communications SARL
Simon Morlat (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <sstream>
#include "generator.hh"
#ifdef WIN32
#include <direct.h>
#endif
CplusplusGenerator::CplusplusGenerator(){
}
void CplusplusGenerator::generate(Project *proj){
list<Class*> classes=proj->getClasses();
mCurProj=proj;
#ifndef WIN32
mkdir(proj->getName().c_str(),S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IROTH);
#else
_mkdir(proj->getName().c_str());
#endif
for_each(classes.begin(),classes.end(),bind1st(mem_fun(&CplusplusGenerator::writeClass),this));
}
void CplusplusGenerator::writeClass(Class *klass){
ostringstream filename;
if (klass->getType()!=Type::Class) return;
filename<<mCurProj->getName()<<"/"<<klass->getName()<<".hh";
mOutfile.open(filename.str().c_str());
if (!mOutfile.is_open()){
cerr<<"Could not write into "<<filename.str()<<endl;
return;
}
const list<Method*> &methods=klass->getMethods();
mCurClass=klass;
mOutfile<<"/* Wrapper generated by lp-gen-wrappers, do not edit*/"<<endl;
mOutfile<<endl;
mOutfile<<"#include <string>"<<endl;
mOutfile<<endl;
if (!mCurProj->getName().empty())
mOutfile<<"namespace "<<mCurProj->getName()<<"{"<<endl<<endl;
mOutfile<<"class "<<klass->getName()<<"{"<<endl;
mOutfile<<"public:"<<endl;
for_each(methods.begin(),methods.end(),bind1st(mem_fun(&CplusplusGenerator::writeMethod),this));
mOutfile<<"}"<<endl<<endl;
if (!mCurProj->getName().empty())
mOutfile<<"} //end of namespace "<<mCurProj->getName()<<endl;
mOutfile<<endl;
mOutfile.close();
}
void CplusplusGenerator::writeArgument(Argument *arg, bool isReturn){
Type *type=arg->getType();
if (type->getBasicType()==Type::Class){
if (arg->isConst()){
mOutfile<<"const ";
}
mOutfile<<type->getName();
if (arg->isPointer())
mOutfile<<"*";
}else if (type->getBasicType()==Type::Integer){
mOutfile<<"int";
}else if (type->getBasicType()==Type::Enum){
mOutfile<<type->getName();
}else if (type->getBasicType()==Type::String){
if (!isReturn)
mOutfile<<"const std::string &";
else
mOutfile<<"std::string";
}else if (type->getBasicType()==Type::Void){
mOutfile<<"void";
}else if (type->getBasicType()==Type::Boolean){
mOutfile<<"bool";
}
if (!isReturn && !arg->getName().empty())
mOutfile<<" "<<arg->getName();
}
void CplusplusGenerator::writeTabs(int ntabs){
int i;
for(i=0;i<ntabs;++i)
mOutfile<<"\t";
}
void CplusplusGenerator::writeHelpComment(const std::string &comment, int ntabs){
size_t i;
int curindex=0;
writeTabs(ntabs);
mOutfile<<" * ";
for(i=0;i<comment.size();i++,curindex++){
if (comment[i]=='\n' || (curindex>100 && comment[i]==' ')){
mOutfile<<endl;
writeTabs(ntabs);
mOutfile<<" * ";
curindex=0;
}else mOutfile<<comment[i];
}
}
void CplusplusGenerator::writeMethod(Method *method){
Argument *retarg=method->getReturnArg();
const list<Argument*> &args=method->getArgs();
list<Argument*>::const_iterator it;
writeTabs(1);
mOutfile<<"/**"<<endl;
writeHelpComment(method->getHelp(),1);
mOutfile<<endl;
writeTabs(1);
mOutfile<<"**/"<<endl;
writeTabs(1);
writeArgument(retarg,true);
mOutfile<<" "<<method->getName()<<"(";
for(it=args.begin();it!=args.end();++it){
if (it!=args.begin()) mOutfile<<", ";
writeArgument(*it);
}
mOutfile<<")";
if (method->isConst()) mOutfile<<"const";
mOutfile<<";"<<endl;
mOutfile<<endl;
}
JavascriptGenerator::JavascriptGenerator(){
}
void JavascriptGenerator::generate(Project *proj){
list<Class*> classes=proj->getClasses();
mCurProj=proj;
#ifndef WIN32
unlink(proj->getName().c_str());
mkdir(proj->getName().c_str(),S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IROTH);
#else
_mkdir(proj->getName().c_str());
#endif
for_each(classes.begin(),classes.end(),bind1st(mem_fun(&JavascriptGenerator::writeClass),this));
}
void JavascriptGenerator::writeClass(Class *klass){
ostringstream filename;
if (klass->getType()!=Type::Class) return;
filename<<mCurProj->getName()<<"/"<<klass->getName()<<".js";
mOutfile.open(filename.str().c_str());
if (!mOutfile.is_open()){
cerr<<"Could not write into "<<filename.str()<<endl;
return;
}
const list<Method*> &methods=klass->getMethods();
mCurClass=klass;
mOutfile<<"/* Wrapper generated by lp-gen-wrappers, do not edit*/"<<endl;
mOutfile<<endl;
//if (!mCurProj->getName().empty())
// mOutfile<<"namespace "<<mCurProj->getName()<<"{"<<endl<<endl;
mOutfile<<"/**"<<endl;
mOutfile<<" * "<<klass->getHelp()<<endl;
mOutfile<<" * @external "<<klass->getName()<<endl;
mOutfile<<"**/"<<endl;
list<Property*> properties=klass->getProperties();
for_each(properties.begin(),properties.end(),bind1st(mem_fun(&JavascriptGenerator::writeProperty),this));
mOutfile<<endl;
for_each(methods.begin(),methods.end(),bind1st(mem_fun(&JavascriptGenerator::writeMethod),this));
//if (!mCurProj->getName().empty())
// mOutfile<<"} //end of namespace "<<mCurProj->getName()<<endl;
mOutfile<<endl;
mOutfile.close();
}
void JavascriptGenerator::writeType(Type *type){
switch(type->getBasicType()){
case Type::Float:
case Type::Integer:
mOutfile<<"number";
break;
case Type::String:
mOutfile<<"string";
break;
case Type::Boolean:
mOutfile<<"boolean";
break;
case Type::Class:
case Type::Enum:
mOutfile<<"external:"<<type->getName();
break;
case Type::Void:
mOutfile<<"void";
break;
case Type::Callback:
break;
}
}
void JavascriptGenerator::writeArgument(Argument *arg, bool isReturn){
if (!isReturn){
mOutfile<<" * @param {";
writeType(arg->getType());
mOutfile<<"} "<<arg->getName()<<" - "<<arg->getHelp()<<endl;
}else{
mOutfile<<" * @returns {";
writeType(arg->getType());
mOutfile<<"} "<<arg->getHelp()<<endl;
}
}
void JavascriptGenerator::writeTabs(int ntabs){
int i;
for(i=0;i<ntabs;++i)
mOutfile<<"\t";
}
void JavascriptGenerator::writeHelpComment(const std::string &comment, int ntabs){
size_t i;
int curindex=0;
mOutfile<<" * ";
for(i=0;i<comment.size();i++,curindex++){
if (comment[i]=='\n' || (curindex>100 && comment[i]==' ')){
mOutfile<<endl;
mOutfile<<" * ";
curindex=0;
}else mOutfile<<comment[i];
}
}
void JavascriptGenerator::writeProperty(Property *prop){
mOutfile<<"/**"<<endl;
writeHelpComment(prop->getHelp(),0);
mOutfile<<endl;
mOutfile<<" * @member {";
writeType(prop->getType());
mOutfile<<"} external:"<<mCurClass->getName()<<"#"<<prop->getName()<<endl;
if (prop->getAttribute()==Property::ReadOnly)
mOutfile<<" * @readonly"<<endl;
mOutfile<<"**/"<<endl;
}
void JavascriptGenerator::writeMethod(Method *method){
Argument *retarg=method->getReturnArg();
const list<Argument*> &args=method->getArgs();
list<Argument*>::const_iterator it;
if (method->getPropertyBehaviour()!=Method::None) return;
if (method->getName()=="ref" || method->getName()=="unref") return;
mOutfile<<"/**"<<endl;
writeHelpComment(method->getHelp(),0);
mOutfile<<endl;
mOutfile<<" * @function external:"<<mCurClass->getName()<<"#"<<method->getName()<<endl;
for(it=args.begin();it!=args.end();++it){
writeArgument(*it);
}
writeArgument(retarg,true);
mOutfile<<"**/"<<endl;
mOutfile<<endl;
}

66
tools/generator.hh Normal file
View file

@ -0,0 +1,66 @@
/*
linphone
Copyright (C) 2013 Belledonne Communications SARL
Simon Morlat (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef generator_hh
#define generator_hh
#include <fstream>
#include "software-desc.hh"
class OutputGenerator{
public:
virtual void generate(Project *proj)=0;
};
class CplusplusGenerator : public OutputGenerator{
public:
CplusplusGenerator();
virtual void generate(Project *proj);
private:
void writeClass(Class *klass);
void writeArgument(Argument *arg, bool isReturn=false);
void writeTabs(int ntabs);
void writeHelpComment(const std::string &comment, int ntabs);
void writeMethod(Method *method);
ofstream mOutfile;
Project *mCurProj;
Class *mCurClass;
};
class JavascriptGenerator : public OutputGenerator{
public:
JavascriptGenerator();
virtual void generate(Project *proj);
private:
void writeClass(Class *klass);
void writeType(Type *type);
void writeArgument(Argument *arg, bool isReturn=false);
void writeTabs(int ntabs);
void writeHelpComment(const std::string &comment, int ntabs);
void writeProperty(Property *prop);
void writeMethod(Method *method);
ofstream mOutfile;
Project *mCurProj;
Class *mCurClass;
};
#endif

View file

@ -18,147 +18,17 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "software-desc.hh"
#include "generator.hh"
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <string.h>
#include <cstdio>
#include <iostream>
#include <list>
#include <map>
#include <sstream>
using namespace::std;
class Type{
public:
enum BasicType{
Integer,
String,
Klass
};
static Type *getType(const std::string &tname){
if (strstr(tname.c_str(),"char")!=0 && strchr(tname.c_str(),'*')!=0){
return &sStringType;
}else if (strcmp(tname.c_str(),"int")==0){
return &sIntegerType;
}else{
Type* ret;
string tmp=tname;
ssize_t pos;
/*really ugly and slow*/
pos=tmp.find('*');
if (pos!=string::npos)
tmp.erase(pos,1);
pos=tmp.find("const");
if (pos!=string::npos)
tmp.erase(pos,strlen("const"));
while ((pos=tmp.find(' '))!=string::npos){
tmp.erase(pos,1);
}
if ((ret=mTypes[tmp])==0){
cout<<"Adding new class type '"<<tmp<<"'"<<endl;
ret=mTypes[tmp]=new Type(Type::Klass,tmp);
}
return ret;
}
cout<<"Unhandled type name"<<tname<<endl;
return NULL;
}
const string &getName()const{
return mName;
}
private:
BasicType mBasic;
string mName;
Type(BasicType basic, const std::string &tname="") : mBasic(basic), mName(tname){
}
static Type sStringType;
static Type sIntegerType;
static std::map<string,Type*> mTypes;
};
Type Type::sStringType(Type::String);
Type Type::sIntegerType(Type::Integer);
std::map<string,Type*> Type::mTypes;
class Argument{
public:
Argument(Type *type, const string &argname, bool isConst) : mType(type), mName(argname), mConst(isConst){
}
Type *getType()const{
return mType;
}
private:
bool mConst;
Type *mType;
string mName;
string mHelp;
};
class Method{
public:
Method(const std::string &uid, Argument* return_arg, const std::string &name, const list<Argument*> &args){
mUid=uid;
mReturn=return_arg;
mName=name;
mArgs=args;
}
void setHelp(const std::string &help){
mHelp=help;
}
private:
string mUid;
Argument *mReturn;
string mName;
list<Argument*> mArgs;
string mHelp;
};
class Class{
public:
Class(const std::string &name): mName(name){
}
void addMethod(Method *method){
mMethods.push_back(method);
}
void setHelp(const std::string &help){
mHelp=help;
}
private:
list<Method*> mMethods;
string mName;
string mHelp;
};
class Project{
public:
Class *getClass(const std::string &name){
Class *ret;
if ((ret=mClasses[name])==NULL){
ret=mClasses[name]=new Class(name);
}
return ret;
}
private:
map<string,Class*> mClasses;
};
static xmlNode * findChild(xmlNode *a_node, const char *element_name){
xmlNode *cur_node;
for (cur_node = a_node->children; cur_node != NULL ; cur_node = cur_node->next){
if (strcmp((const char*)cur_node->name,(const char*)element_name)==0){
return cur_node;
}
}
return NULL;
}
static bool isSpace(const char *str){
for(;*str!='\0';++str){
@ -167,45 +37,101 @@ static bool isSpace(const char *str){
return true;
}
static string findChildContent(xmlNode *a_node, const char *element_name){
xmlNode *node=findChild(a_node,element_name);
string res;
if (node) {
xmlChar *text=xmlNodeGetContent(node);
if (!isSpace((const char*)text))
res=(char*)text;
xmlFree(text);
//Convenient class for examining node recursively
class XmlNode{
public:
XmlNode(const xmlNode *node=NULL) : mNode(node){
}
return res;
}
XmlNode getChild(const string &name)const{
if (mNode==NULL) return XmlNode();
xmlNode *it;
for(it=mNode->children;it!=NULL;it=it->next){
if (xmlStrcmp(it->name,(const xmlChar*)name.c_str())==0)
return XmlNode(it);
}
return XmlNode();
}
XmlNode getChildRecursive(const string &name)const{
if (mNode==NULL) return XmlNode();
xmlNode *it;
//find in direct children
for(it=mNode->children;it!=NULL;it=it->next){
if (xmlStrcmp(it->name,(const xmlChar*)name.c_str())==0)
return XmlNode(it);
}
//recurse into children
for(it=mNode->children;it!=NULL;it=it->next){
XmlNode res=XmlNode(it).getChildRecursive(name);
if (!res.isNull()) return res;
}
return XmlNode();
}
list<XmlNode> getChildren(const string &name)const{
xmlNode *it;
list<XmlNode> nodes;
if (mNode==NULL) return nodes;
for(it=mNode->children;it!=NULL;it=it->next){
if (xmlStrcmp(it->name,(const xmlChar*)name.c_str())==0)
nodes.push_back(XmlNode(it));
}
if (nodes.empty()) cerr<<"getChildren() no "<<name<<" found"<<endl;
return nodes;
}
string getText()const{
if (mNode==NULL) return "";
XmlNode node=getChild("text");
if (!node.isNull()) {
const char *text=(const char*)node.mNode->content;
if (!isSpace(text)) return string(text);
}
return "";
}
string getProp(const string &propname)const{
if (mNode==NULL) return "";
xmlChar *value;
value=xmlGetProp((xmlNode*)mNode,(const xmlChar*)propname.c_str());
if (value) return string((const char*)value);
return "";
}
bool isNull()const{
return mNode==NULL;
}
private:
const xmlNode *mNode;
};
#define nullOrEmpty(p) (p==NULL || *p=='\0')
static Argument *parseArgument(xmlNode *node){
string name=findChildContent(node,"name");
static Argument *parseArgument(XmlNode node, bool isReturn){
string name=node.getChild("declname").getText();
Type *type=NULL;
string typecontent=node.getChild("type").getText();
bool isConst=false;
bool isPointer=false;
xmlNode *typenode=findChild(node,"type");
//find documented type if any
string tname=node.getChild("type").getChild("ref").getText();
if (!tname.empty()){
type=Type::getType(tname);
}else type=Type::getType(typecontent);
if (!typenode) {
cout<<"Cannot find type from node."<<endl;
return NULL;
}
//find const attribute if any
if (typecontent.find("const")!=string::npos)
isConst=true;
if (typecontent.find("*")!=string::npos)
isPointer=true;
string tname=findChildContent(typenode,"ref");
if (tname.empty()){
return NULL;
}
Type *type=Type::getType(tname);
if (type==NULL) {
return NULL;
}
return new Argument(type,name,false);
//cout<<"Parsed argument "<<name<<" with type "<<type->getBasicType()<<" "<<type->getName()<<endl;
return new Argument(type,!isReturn ? name : "",isConst,isPointer);
}
static string classNameToPrefix(const std::string &classname){
char tmp[classname.size()*2];
char *w=tmp;
ssize_t i;
size_t i;
for(i=0;i<classname.size();i++){
char p=classname[i];
@ -223,7 +149,7 @@ static string classNameToPrefix(const std::string &classname){
static string makeMethodName(const string & suffix){
char tmp[suffix.size()];
char *w=tmp;
ssize_t i;
size_t i;
bool useUpper=false;
for(i=0;i<suffix.size();i++){
@ -252,50 +178,106 @@ static string extractMethodName(const string &c_name, const std::string& class_n
return "";
}
static string getHelpBody(XmlNode myNode){
ostringstream result;
XmlNode brief=myNode.getChild("briefdescription");
XmlNode detailed=myNode.getChild("detaileddescription");
result<<brief.getText();
result<<detailed.getChild("para").getText();
//cout<<"getHelpBody():"<<result.str();
return result.str();
}
static void parseFunction(Project *proj, xmlNode *node){
string name;
Argument *first_arg=NULL;
xmlNode *cur_node;
string className;
string methodName;
Argument *retarg=NULL;
list<Argument*> args;
string help;
XmlNode funcnode(node);
XmlNode parameterlist;
list<XmlNode> params;
list<XmlNode> paramsHelp;
list<XmlNode>::iterator it,helpit;
for (cur_node = node->children; cur_node != NULL ; cur_node = cur_node->next){
if (strcmp((const char*)cur_node->name,"name")==0){
xmlChar *content=xmlNodeGetContent(cur_node);
name=(const char*)content;
xmlFree(content);
}else if (strcmp((const char*)cur_node->name,"param")==0){
if (first_arg==NULL){
first_arg=parseArgument(cur_node);
name=funcnode.getChild("name").getText();
params=funcnode.getChildren("param");
parameterlist=funcnode.getChild("detaileddescription").getChildRecursive("parameterlist");
if (parameterlist.isNull()) cerr<<"parameterlist not found"<<endl;
paramsHelp=parameterlist.getChildren("parameteritem");
for (it=params.begin(),helpit=paramsHelp.begin();it!=params.end();++it){
Argument *a=parseArgument(*it,false);
if (a){
//add argument help
if (!args.empty()){
if (helpit!=paramsHelp.end()){
XmlNode item=*helpit;
a->setHelp(item.getChild("parameterdescription").getChild("para").getText());
}else cerr<<"Undocumented parameter "<<a->getName()<<" in function "<<name<<endl;
}
args.push_back(a);
if (helpit!=paramsHelp.end()) ++helpit;
}
else return;
}
help=getHelpBody(funcnode);
retarg=parseArgument(funcnode,true);
if (!retarg){
cerr<<"Could not parse return argument of function "<<name<<endl;
return;
}
if (!args.empty()) first_arg=args.front();
if (!first_arg){
cout<<"Could not determine first argument of "<<name<<endl;
return;
}
if (first_arg->getType()->getBasicType()!=Type::Class) return;
className=first_arg->getType()->getName();
methodName=extractMethodName(name,className);
if (!methodName.empty()){
cout<<"Found "<<className<<"."<<methodName<<"()"<<endl;
if (!methodName.empty() && methodName!="destroy"){
//cout<<"Found "<<className<<"."<<methodName<<"()"<<endl;
args.pop_front();
Method *method=new Method("",retarg,methodName,args,first_arg->isConst(),false);
method->setHelp(help);
proj->getClass(className)->addMethod(method);
delete first_arg;
}
}
static void parseTypedef(Project *proj, xmlNode *node){
XmlNode tdef(node);
string typecontent=tdef.getChild("type").getText();
string name=tdef.getChild("name").getText();
if (typecontent.find("enum")==0){
Type::addType(Type::Enum,name);
}else if (typecontent.find("void(*")==0){
// callbacks function, not really well parsed by doxygen
Type::addType(Type::Callback,name);
}else
proj->getClass(name)->setHelp(getHelpBody(node));
}
static void parseMemberDef(Project *proj, xmlNode *node){
XmlNode member(node);
string brief;
string detailed;
const xmlChar *kind;
string kind;
brief=findChildContent(node,"briefdescription");
detailed=findChildContent(node,"detaileddescription");
if (brief.empty() && detailed.empty())
if (member.getChild("briefdescription").getText().empty() &&
member.getChild("detaileddescription").getChild("para").getText().empty())
return;
kind=xmlGetProp(node,(const xmlChar*)"kind");
//cout<<"Kind="<<(const char*)kind<<endl;
if (kind && xmlStrcmp(kind,(const xmlChar*)"function")==0){
kind=member.getProp("kind");
if (kind=="function"){
parseFunction(proj,node);
}else if (kind=="typedef"){
parseTypedef(proj,node);
}
}
@ -334,23 +316,46 @@ static int parse_file(Project *proj, const char *filename){
/*free the document */
xmlFreeDoc(doc);
return 0;
}
int main(int argc, char *argv[]){
int i;
Project *proj=new Project();
OutputGenerator *gen=NULL;
list<string> files;
list<string>::iterator it;
LIBXML_TEST_VERSION
for(i=1;i<argc;i++){
if (strcmp(argv[i],"--help")==0){
fprintf(stderr,"%s: [--help] file1 file2...\nParses xml files generated by doxygen to output wrappers in a specified language.\n",argv[0]);
fprintf(stderr,"%s: [--help] --output (c++) file1 file2...\nParses xml files generated by doxygen to output wrappers in a specified language.\n",argv[0]);
return -1;
}if (strcmp(argv[i],"--output")==0){
i++;
if (strcmp(argv[i],"c++")==0){
gen=new CplusplusGenerator();
}else if (strcmp(argv[i],"javascript")==0){
gen=new JavascriptGenerator();
}
}else{
if (parse_file(proj,argv[i])==-1)
break;
files.push_back(argv[i]);
}
}
if (gen==NULL) {
cerr<<"No output generator selected !"<<endl;
return -1;
}
for(it=files.begin();it!=files.end();it++){
if (parse_file(proj,(*it).c_str())==-1){
cerr<<"Parsing aborted."<<endl;
return -1;
}
}
proj->analyse();
gen->generate(proj);
return 0;
}
}

40
tools/software-desc.cc Normal file
View file

@ -0,0 +1,40 @@
/*
linphone
Copyright (C) 2013 Belledonne Communications SARL
Simon Morlat (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "software-desc.hh"
Type Type::sStringType(Type::String);
Type Type::sIntegerType(Type::Integer);
Type Type::sVoidType(Type::Void);
Type Type::sBooleanType(Type::Boolean);
Type Type::sFloatType(Type::Float);
std::map<string,Type*> Type::mTypes;
const char *Type::sBasicTypeNames[]={
"Void",
"Boolean",
"Integer",
"Float",
"String",
"Enum",
"Class",
"Callback",
"undef",
"undef"
};

369
tools/software-desc.hh Normal file
View file

@ -0,0 +1,369 @@
/*
linphone
Copyright (C) 2013 Belledonne Communications SARL
Simon Morlat (simon.morlat@linphone.org)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef software_desc_hh
#define software_desc_hh
#include <iostream>
#include <list>
#include <map>
#include <algorithm>
#include <sys/types.h>
#include <sys/stat.h>
#include <cstring>
using namespace::std;
class Type{
public:
enum BasicType{
Void,
Boolean,
Integer,
Float,
String,
Enum,
Class,
Callback
};
static const char *sBasicTypeNames[];
static Type* addType(BasicType bt, const string &name){
Type* ret;
if ((ret=mTypes[name])==0){
//cout<<"Adding new "<<sBasicTypeNames[(int)bt]<<" type '"<<name<<"'"<<endl;
ret=mTypes[name]=new Type(bt,name);
}else if (bt!=Class){
ret->mBasic=bt;
}
return ret;
}
static Type *getType(const std::string &tname){
if (strstr(tname.c_str(),"char")!=0 && strchr(tname.c_str(),'*')!=0){
return &sStringType;
}else if (tname.find("int")==0){
return &sIntegerType;
}else if (tname.find("float")==0){
return &sFloatType;
}else if (tname.find("bool_t")==0){
return &sBooleanType;
}else if (tname.find("void")!=string::npos){
return &sVoidType;
}else if (tname.find("enum")==0){
return addType(Enum,tname.c_str()+strlen("enum "));
}else{/*an object?*/
string tmp=tname;
size_t pos;
/*really ugly and slow*/
pos=tmp.find('*');
if (pos!=string::npos)
tmp.erase(pos,1);
pos=tmp.find("const");
if (pos!=string::npos)
tmp.erase(pos,strlen("const"));
while ((pos=tmp.find(' '))!=string::npos){
tmp.erase(pos,1);
}
return addType(Class,tmp);
}
cerr<<"Unhandled type name"<<tname<<endl;
return NULL;
}
const string &getName()const{
return mName;
}
BasicType getBasicType()const{
return mBasic;
}
private:
BasicType mBasic;
string mName;
Type(BasicType basic, const std::string &tname="") : mBasic(basic), mName(tname){
}
static Type sStringType;
static Type sIntegerType;
static Type sVoidType;
static Type sBooleanType;
static Type sFloatType;
static std::map<string,Type*> mTypes;
};
class Argument{
public:
Argument(Type *type, const string &argname, bool isConst, bool isPointer) : mType(type), mName(argname), mConst(isConst), mPointer(isPointer){
if (!isPointer) mConst=false;
}
Type *getType()const{
return mType;
}
bool isConst()const{
return mConst;
}
const string &getName()const{
return mName;
}
bool isPointer()const{
return mPointer;
}
const string &getHelp()const{
return mHelp;
}
void setHelp(const string &help){
mHelp=help;
}
private:
Type *mType;
string mName;
string mHelp;
bool mConst;
bool mPointer;
};
class Method{
public:
enum PropertyBehaviour{
None,
Read,
Write
};
Method(const std::string &uid, Argument* return_arg, const std::string &name, const list<Argument*> &args, bool isConst, bool isStatic){
mUid=uid;
mReturn=return_arg;
mName=name;
mArgs=args;
mConst=isConst;
mStatic=isStatic;
analyseProperties();
}
void setHelp(const std::string &help){
mHelp=help;
}
Argument *getReturnArg()const{
return mReturn;
}
const string &getName()const{
return mName;
}
const list<Argument*> &getArgs()const {
return mArgs;
}
bool isConst()const{
return mConst;
}
bool isStatic()const{
return mStatic;
}
const string &getHelp(){
return mHelp;
}
PropertyBehaviour getPropertyBehaviour()const{
return mPropertyBehaviour;
}
const string &getPropertyName()const{
return mPropertyName;
}
private:
void analyseProperties(){
size_t enabled_pos;
mPropertyBehaviour=None;
if (mName.find("get")==0 && mArgs.size()==0){
mPropertyName=mName.substr(3,string::npos);
if (!mPropertyName.empty()){
mPropertyName[0]=tolower(mPropertyName[0]);
mPropertyBehaviour=Read;
}
}else if (mName.find("enable")==0 && mArgs.size()==1){
mPropertyName=mName.substr(6,string::npos);
if (!mPropertyName.empty()){
mPropertyName[0]=tolower(mPropertyName[0]);
mPropertyBehaviour=Write;
}
}else if (mName.find("set")==0 && mArgs.size()==1){
mPropertyName=mName.substr(3,string::npos);
if (!mPropertyName.empty()){
mPropertyName[0]=tolower(mPropertyName[0]);
mPropertyBehaviour=Write;
}
}else if ((enabled_pos=mName.rfind("Enabled"))!=string::npos && mArgs.size()==0){
size_t goodpos=mName.size()-7;
if (enabled_pos==goodpos){
mPropertyName=mName.substr(0,goodpos);
if (!mPropertyName.empty()){
mPropertyBehaviour=Read;
}
}
}
if (mPropertyBehaviour==None)
mPropertyName="";
}
string mUid;
Argument *mReturn;
string mName;
list<Argument*> mArgs;
string mHelp;
string mPropertyName; /*if it can be a property*/
PropertyBehaviour mPropertyBehaviour;
bool mConst;
bool mStatic;
};
class Property{
public:
enum Attribute{
ReadOnly,
ReadWrite
};
Property(Attribute attr, const string &name, Type *type, const string &help) : mAttr(attr), mName(name), mType(type), mHelp(help){
}
const string &getName()const{
return mName;
}
const string &getHelp()const{
return mHelp;
}
void setHelp(const string &help){
mHelp=help;
}
Attribute getAttribute()const{
return mAttr;
}
void setAttribute(Attribute attr){
mAttr=attr;
}
Type* getType()const{
return mType;
}
private:
Attribute mAttr;
string mName;
Type *mType;
string mHelp;
};
/*actually a class or an enum*/
class Class{
public:
Class(const std::string &name): mName(name){
}
Type::BasicType getType(){
return Type::getType(mName)->getBasicType();
}
void addMethod(Method *method){
if (mMethods.find(method->getName())==mMethods.end())
mMethods.insert(make_pair(method->getName(),method));
}
void setHelp(const std::string &help){
mHelp=help;
}
const list<Method*> getMethods()const{
list<Method*> ret;
map<string,Method*>::const_iterator it;
for(it=mMethods.begin();it!=mMethods.end();++it){
ret.push_back((*it).second);
}
return ret;
}
const string &getName()const{
return mName;
}
const string &getHelp()const{
return mHelp;
}
const list<Property*> getProperties(){
list<Property*> ret;
map<string,Property*>::const_iterator it;
for(it=mProperties.begin();it!=mProperties.end();++it){
ret.push_back((*it).second);
}
return ret;
}
void computeProperties(){
map<string,Method*>::const_iterator it;
Property *prop;
for (it=mMethods.begin();it!=mMethods.end();++it){
Method *m=(*it).second;
if (m->getPropertyBehaviour()==Method::Read){
prop=mProperties[m->getPropertyName()];
if (prop==NULL){
prop=new Property(Property::ReadOnly,m->getPropertyName(),m->getReturnArg()->getType(), m->getHelp());
mProperties[m->getPropertyName()]=prop;
}
}else if (m->getPropertyBehaviour()==Method::Write){
prop=mProperties[m->getPropertyName()];
if (prop==NULL){
prop=new Property(Property::ReadWrite,m->getPropertyName(),m->getArgs().front()->getType(), m->getHelp());
mProperties[m->getPropertyName()]=prop;
}else{
prop->setHelp(m->getHelp());
prop->setAttribute(Property::ReadWrite);
}
}
}
}
private:
map<string,Method*> mMethods;
map<string,Property*> mProperties;
string mName;
string mHelp;
};
class Project{
public:
Project(const string &name="wrapper") : mName(name){
}
Class *getClass(const std::string &name){
Class *ret;
if ((ret=mClasses[name])==NULL){
ret=mClasses[name]=new Class(name);
}
return ret;
}
list<Class*> getClasses()const{
list<Class*> ret;
map<string,Class*>::const_iterator it;
for(it=mClasses.begin();it!=mClasses.end();++it){
ret.push_back((*it).second);
}
return ret;
}
const string &getName()const{
return mName;
}
void analyse(){
list<Class*> classes=getClasses();
for_each(classes.begin(),classes.end(),mem_fun(&Class::computeProperties));
}
private:
map<string,Class*> mClasses;
string mName;
};
#endif