Remove useless files.

This commit is contained in:
Ghislain MARY 2018-04-19 17:30:51 +02:00
parent aefe2c8ee8
commit a891e599b6
5 changed files with 0 additions and 1522 deletions

View file

@ -1,454 +0,0 @@
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <sstream>
#include "generator.hh"
#ifdef _WIN32
#include <direct.h>
#define strncasecmp _strnicmp
#endif
string to_lower(const string &str){
string res=str;
for(string::iterator it=res.begin();it!=res.end();++it){
*it=tolower(*it);
}
return res;
}
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::writeEnumMember(ConstField *cf, bool isLast){
writeTabs(1);
mOutfile<<cf->getName()<<"="<<cf->getValue();
if (!isLast) mOutfile<<",";
if (!cf->getHelp().empty()) mOutfile<<"\t/**< "<<cf->getHelp()<<" */";
mOutfile<<endl;
}
void CplusplusGenerator::writeClass(Class *klass){
ostringstream filename;
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;
}
list<Method*> methods=klass->getMethods();
list<ConstField*> constFields=klass->getConstFields();
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;
if (klass->getType()==Type::Enum){
mOutfile<<"enum "<<klass->getName()<<"{"<<endl;
list<ConstField*>::iterator cfit,next;
for (cfit=constFields.begin();cfit!=constFields.end();){
ConstField *cf=*cfit;
writeEnumMember(cf,++cfit==constFields.end());
}
}else{
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){
if (method->isCallback()) return;
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
remove(to_lower(proj->getName()).c_str());
mkdir(to_lower(proj->getName()).c_str(),S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IROTH);
#else
_mkdir(to_lower(proj->getName()).c_str());
#endif
ostringstream filename;
/*write a file for the namespace*/
filename<<to_lower(mCurProj->getName())<<"/"<<to_lower(mCurProj->getName())<<".js";
mOutfile.open(filename.str().c_str());
if (!mOutfile.is_open()){
cerr<<"Could not write into "<<filename.str()<<endl;
return;
}
mOutfile<<"/**"<<endl;
mOutfile<<" * Namespace for non-external variables and objects."<<endl;
mOutfile<<" * @namespace "<<mCurProj->getName()<<endl;
mOutfile<<"**/"<<endl;
mOutfile<<"var "<<proj->getName()<<" = {};"<<endl;
mOutfile.close();
for_each(classes.begin(),classes.end(),bind1st(mem_fun(&JavascriptGenerator::writeEnum),this));
for_each(classes.begin(),classes.end(),bind1st(mem_fun(&JavascriptGenerator::writeClass),this));
}
string JavascriptGenerator::getEnumName(Class *klass){
string enum_name=klass->getName();
if (strncasecmp(enum_name.c_str(),mCurProj->getName().c_str(),mCurProj->getName().size())==0){
//since enum is part of the namespace, drop the namespace part of the enum if any.
enum_name.erase(0,mCurProj->getName().size());
}
return enum_name;
}
void JavascriptGenerator::writeEnum(Class *klass){
if (klass->getType()!=Type::Enum) return;
ostringstream filename;
list<ConstField*> members=klass->getConstFields();
list<ConstField*>::iterator it;
string enum_name=getEnumName(klass);
filename<<to_lower(mCurProj->getName())<<"/"<<to_lower(enum_name)<<".js";
mOutfile.open(filename.str().c_str());
if (!mOutfile.is_open()){
cerr<<"Could not write into "<<filename.str()<<endl;
return;
}
mOutfile<<"/* Wrapper generated by lp-gen-wrappers, do not edit*/"<<endl<<endl;
mOutfile<<"var "<<mCurProj->getName()<<" = "<<mCurProj->getName()<<" || {};"<<endl;
mOutfile<<"/**"<<endl;
writeHelpComment(klass->getHelp(),0);
mOutfile<<endl;
mOutfile<<" * "<<"@readonly"<<endl;
mOutfile<<" * "<<"@enum {number}"<<endl;
mOutfile<<"**/"<<endl;
mOutfile<<mCurProj->getName()<<"."<<enum_name<<" = {"<<endl;
string prefix=ConstField::getCommonPrefix(members);
size_t prefix_size=prefix.size();
for(it=members.begin();it!=members.end();){
ConstField *cf=(*it);
if (!cf->getHelp().empty()){
writeTabs(1);
mOutfile<<"/**"<<endl;
writeHelpComment(cf->getHelp(),1);
mOutfile<<endl;
writeTabs(1);
mOutfile<<"*/"<<endl;
}
writeTabs(1);
mOutfile<<cf->getName().substr(prefix_size,string::npos)<<" : "<<cf->getValue();
if (++it!=members.end()) mOutfile<<",";
mOutfile<<endl;
}
mOutfile<<"};"<<endl;
mOutfile << "/**" << endl;
mOutfile << " * Get the name of a value of the " << enum_name << " enum as a string." << endl;
mOutfile << " * @function linphone#get" << enum_name << "Text" << endl;
mOutfile << " * @param { number } value - One of the values of the " << enum_name << " enum." << endl;
mOutfile << "**/" << endl;
mOutfile << mCurProj->getName() << ".get" << enum_name << "Text = function(value) {" << endl;
mOutfile << "\tswitch (value) {" << endl;
for (it = members.begin(); it != members.end(); it++) {
ConstField *cf = *it;
mOutfile << "\tcase " << mCurProj->getName() << "." << enum_name << "." << cf->getName().substr(prefix_size, string::npos) << ":" << endl;
mOutfile << "\t\treturn \"" << cf->getName().substr(prefix_size, string::npos) << "\";" << endl;
}
mOutfile << "\tdefault:" << endl;
mOutfile << "\t\treturn \"?\";" << endl;
mOutfile << "\t}" << endl;
mOutfile << "};" << endl;
mOutfile.close();
}
void JavascriptGenerator::writeClass(Class *klass){
ostringstream filename;
if (klass->getType()==Type::Enum) {
return;
}
const list<Method*> &methods=klass->getMethods();
if (methods.empty()) return;//skip empty classes
filename<<to_lower(mCurProj->getName())<<"/"<<to_lower(klass->getName())<<".js";
mOutfile.open(filename.str().c_str());
if (!mOutfile.is_open()){
cerr<<"Could not write into "<<filename.str()<<endl;
return;
}
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));
for_each(methods.begin(),methods.end(),bind1st(mem_fun(&JavascriptGenerator::writeEvent),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:
mOutfile<<"external:"<<type->getName();
break;
case Type::Enum:
mOutfile<<mCurProj->getName()<<"."<<getEnumName(mCurProj->getClass(type->getName()));
break;
case Type::Void:
mOutfile<<"void";
break;
case Type::Callback:
break;
case Type::Array:
mOutfile<<"Array.<Object>";
break;
}
}
void JavascriptGenerator::writeArgument(Argument *arg, ArgKind kind){
switch(kind){
case Normal:
mOutfile<<" * @param {";
writeType(arg->getType());
mOutfile<<"} "<<arg->getName()<<" - "<<arg->getHelp()<<endl;
break;
case Return:
mOutfile<<" * @returns {";
writeType(arg->getType());
mOutfile<<"} "<<arg->getHelp()<<endl;
break;
case PropertyArg:
mOutfile<<" * @property {";
writeType(arg->getType());
mOutfile<<"} "<<arg->getName()<<" - "<<arg->getHelp()<<endl;
break;
}
}
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;
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 JavascriptGenerator::writeProperty(Property *prop){
if (prop->getName()=="userData" || prop->getName()=="userPointer") return;
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->isCallback()) return;
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,Return);
mOutfile<<"**/"<<endl;
mOutfile<<endl;
}
string JavascriptGenerator::getEventHelp(const string &help){
size_t i=help.find("Callback");
if (i==string::npos){
i=help.find("callback");
if (i==string::npos) return help;
}
string res(help);
res.replace(i,8,"event");
return res;
}
void JavascriptGenerator::writeEvent(Method* event){
const list<Argument*> &args=event->getArgs();
list<Argument*>::const_iterator it;
if (!event->isCallback()) return;
mOutfile<<"/**"<<endl;
writeHelpComment(getEventHelp(event->getHelp()),0);
mOutfile<<endl;
mOutfile<<" * @event external:"<<mCurClass->getName()<<"#"<<event->getName()<<endl;
mOutfile<<" * @type {object}"<<endl;
for(it=args.begin();it!=args.end();++it){
writeArgument(*it,PropertyArg);
}
mOutfile<<"**/"<<endl;
mOutfile<<endl;
}

View file

@ -1,73 +0,0 @@
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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);
void writeEnumMember(ConstField *cf, bool isLast);
ofstream mOutfile;
Project *mCurProj;
Class *mCurClass;
};
class JavascriptGenerator : public OutputGenerator{
public:
JavascriptGenerator();
virtual void generate(Project *proj);
private:
void writeClass(Class *klass);
void writeEnum(Class *klass);
void writeType(Type *type);
enum ArgKind { Normal, Return, PropertyArg};
void writeArgument(Argument *arg, ArgKind kind=Normal);
void writeTabs(int ntabs);
void writeHelpComment(const std::string &comment, int ntabs);
void writeProperty(Property *prop);
void writeMethod(Method *method);
void writeEvent(Method *event);
string getEventHelp(const string &ref);
string getEnumName(Class *klass);
ofstream mOutfile;
Project *mCurProj;
Class *mCurClass;
};
string to_lower(const string &str);
#endif

View file

@ -1,482 +0,0 @@
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "software-desc.hh"
#include "generator.hh"
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <string.h>
#include <cstdio>
#include <iostream>
#include <sstream>
static bool isSpace(const char *str){
for(;*str!='\0';++str){
if (!isspace(*str)) return false;
}
return true;
}
//Convenient class for examining node recursively
class XmlNode{
public:
XmlNode(const xmlNode *node=NULL) : mNode(node){
}
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;
};
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;
//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);
//find const attribute if any
if (typecontent.find("const")!=string::npos)
isConst=true;
if (typecontent.find("*")!=string::npos)
isPointer=true;
if (type==NULL) {
return NULL;
}
//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 = new char[classname.size()*2];
char *w=tmp;
size_t i;
for(i=0;i<classname.size();i++){
char p=classname[i];
if (isupper(p)){
if (i!=0){
*w++='_';
}
*w++=tolower(p);
}else *w++=p;
}
*w++='\0';
string ret(tmp);
delete[] tmp;
return ret;
}
static string makeMethodName(const string & suffix){
char *tmp = new char[suffix.size()];
char *w=tmp;
size_t i;
bool useUpper=false;
for(i=0;i<suffix.size();i++){
char p=suffix[i];
if (p=='_'){
if (i>0)
useUpper=true;
}else{
if (useUpper)
*w++=toupper(p);
else
*w++=p;
useUpper=false;
}
}
*w++='\0';
string ret(tmp);
delete[] tmp;
return ret;
}
static string extractMethodName(const string &c_name, const std::string& class_name){
string prefix=classNameToPrefix(class_name);
if (c_name.find(prefix)==0){
return makeMethodName(c_name.substr(prefix.size(),string::npos));
}
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;
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;
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){
cerr<<"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() && 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 string findCommon(const string &c1, const string & c2){
size_t i;
ostringstream res;
for(i=0;i<c1.size() && i<c2.size();++i){
if (tolower(c1[i])==tolower(c2[i]))
res<<(char)c1[i];
else break;
}
return res.str();
}
static string extractCallbackName(const string &c_name, const string & classname){
string prefix=findCommon(c_name,classname);
string res=c_name.substr(prefix.size(),string::npos);
res[0]=tolower(res[0]);
size_t pos=res.find("Cb");
if (pos!=string::npos) res=res.substr(0,pos);
return res;
}
static void parseCallback(Project *proj, XmlNode node){
string argsstring=node.getChild("argsstring").getText();
string name=node.getChild("name").getText();
list<XmlNode> params=node.getChildRecursive("parameterlist").getChildren("parameteritem");
list<XmlNode>::iterator it=params.begin();
string rettype=node.getChild("type").getText();
argsstring=argsstring.substr(argsstring.find('(')+1,string::npos);
bool cont=true;
list<Argument*> args;
Type *firstArgType=NULL;
rettype=rettype.substr(0,rettype.find('('));
Argument *retarg=new Argument(Type::getType(rettype),"",false,rettype.find('*')!=string::npos);
do{
size_t comma=argsstring.find(',');
size_t end=argsstring.find(')');
if (comma!=string::npos && comma<end) end=comma;
else cont=false;
string arg=argsstring.substr(0,end);
bool isConst=false;
bool isPointer=false;
size_t endtype=arg.find('*');
if (endtype==string::npos) endtype=arg.rfind(' ');
else isPointer=true;
string typestring=arg.substr(0,endtype+1);
Type *type=Type::getType(typestring);
if (type==NULL) return;
if (firstArgType==NULL) firstArgType=type;
//find const attribute if any
if (typestring.find("const")!=string::npos)
isConst=true;
string argname=arg.substr(endtype+1,end);
argsstring=argsstring.substr(end+1,string::npos);
Argument *argobj=new Argument(type,makeMethodName(argname),isConst,isPointer);
if (it!=params.end()){
argobj->setHelp((*it).getChild("parameterdescription").getChild("para").getText());
++it;
}
args.push_back(argobj);
}while(cont);
if (firstArgType->getBasicType()!=Type::Class) return;
Class *klass=proj->getClass(firstArgType->getName());
Method *callback=new Method("", retarg, extractCallbackName(name,klass->getName()), args, false, false, true);
//cout<<"Found callback "<<callback->getName()<<" with "<<args.size()<<" arguments."<<endl;
callback->setHelp(node.getChild("detaileddescription").getChild("para").getText());
klass->addMethod(callback);
}
static void parseEnum(Project *proj, XmlNode node){
string name=node.getChild("name").getText();
if (name[0]=='_') name.erase(0,1);
Class *klass=proj->getClass(name);
klass->setHelp(node.getChild("detaileddescription").getChild("para").getText());
list<XmlNode> enumValues=node.getChildren("enumvalue");
list<XmlNode>::iterator it;
int value = 0;
for (it=enumValues.begin();it!=enumValues.end();++it){
string initializer = (*it).getChild("initializer").getText();
if ((initializer.length() > 1) && (initializer.at(0) == '=')) {
std::stringstream ss;
if ((initializer.length() > 2) && (initializer.at(1) == '0')) {
if ((initializer.length() > 3) && (initializer.at(2) == 'x')) {
ss << std::hex << initializer.substr(3);
} else {
ss << std::oct << initializer.substr(2);
}
} else {
ss << std::dec << initializer.substr(1);
}
ss >> value;
}
ConstField *cf=new ConstField(Type::getType("int"),(*it).getChild("name").getText(),value);
cf->setHelp((*it).getChild("detaileddescription").getChild("para").getText());
klass->addConstField(cf);
value++;
}
}
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("(*")!=string::npos){
parseCallback(proj,node);
}else
proj->getClass(name)->setHelp(getHelpBody(node));
}
static void parseMemberDef(Project *proj, xmlNode *node){
XmlNode member(node);
string brief;
string detailed;
string kind;
if (member.getChild("briefdescription").getText().empty() &&
member.getChild("detaileddescription").getChild("para").getText().empty())
return;
if (member.getProp("id").find("group__")!=0)
return;
if (member.getChild("detaileddescription").getChildRecursive("xreftitle").getText()=="Deprecated")
return;
kind=member.getProp("kind");
if (kind=="function"){
parseFunction(proj,node);
}else if (kind=="typedef"){
parseTypedef(proj,node);
}else if (kind=="enum"){
parseEnum(proj,node);
}
}
static void inspectNode(Project *proj, xmlNode *a_node){
xmlNode *cur_node;
for (cur_node = a_node; cur_node != NULL ; cur_node = cur_node->next) {
if (cur_node->type == XML_ELEMENT_NODE) {
//printf("node type: Element, name: %s\n", cur_node->name);
if (strcmp((const char*)cur_node->name,"memberdef")==0 ){
//cout<<"Found memberdef"<<endl;
parseMemberDef(proj,cur_node);
}
}
if (cur_node->children) inspectNode(proj,cur_node->children);
}
}
static int parse_file(Project *proj, const char *filename){
xmlDoc *doc = NULL;
xmlNode *root_element = NULL;
/*parse the file and get the DOM */
doc = xmlReadFile(filename, NULL, XML_PARSE_RECOVER);
if (doc == NULL) {
cerr<<"xmlReadFile failed."<<endl;
return -1;
}
/*Get the root element node */
root_element = xmlDocGetRootElement(doc);
inspectNode(proj,root_element);
/*free the document */
xmlFreeDoc(doc);
return 0;
}
int main(int argc, char *argv[]){
int i;
string projectName="wrapper";
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] --output (c++, javascript) --project <project name> file1 file2...\nParses xml files generated by doxygen to output wrappers in a specified language.\n",argv[0]);
return -1;
}else 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 (strcmp(argv[i],"--project")==0){
i++;
projectName=argv[i];
}else{
files.push_back(argv[i]);
}
}
if (gen==NULL) {
cerr<<"No output generator selected !"<<endl;
return -1;
}
Project *proj=new Project(projectName);
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;
}

View file

@ -1,43 +0,0 @@
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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);
Type Type::sArrayType(Type::Array);
std::map<string,Type*> Type::mTypes;
const char *Type::sBasicTypeNames[]={
"Void",
"Boolean",
"Integer",
"Float",
"String",
"Enum",
"Class",
"Callback",
"Array",
"undef",
"undef"
};

View file

@ -1,470 +0,0 @@
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef software_desc_hh
#define software_desc_hh
#include <functional>
#include <iostream>
#include <list>
#include <map>
#include <algorithm>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <cstring>
class Type{
public:
enum BasicType{
Void,
Boolean,
Integer,
Float,
String,
Enum,
Class,
Callback,
Array
};
static const char *sBasicTypeNames[];
static Type* addType(BasicType bt, const std::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::std::string &tname){
if (tname.find("(")!=std::string::npos) return NULL; //arrives when parsing function pointer declared inside function prototype
if (strstr(tname.c_str(),"char")!=0 && strchr(tname.c_str(),'*')!=0){
return &sStringType;
}else if (tname.find("int")!=std::string::npos){
return &sIntegerType;
}else if (tname.find("size_t")!=std::string::npos){
return &sIntegerType;
}else if (tname.find("float")!=std::string::npos){
return &sFloatType;
}else if (tname.find("bool_t")!=std::string::npos){
return &sBooleanType;
}else if (tname.find("void")!=std::string::npos){
return &sVoidType;
}else if (tname.find("enum")!=std::string::npos){
return addType(Enum,tname.c_str()+strlen("enum "));
}else if (tname.find("MSList")!=std::string::npos){
return &sArrayType;
}else{/*an object?*/
std::string tmp=tname;
size_t pos;
/*really ugly and slow*/
pos=tmp.find('*');
if (pos!=std::string::npos)
tmp.erase(pos,1);
pos=tmp.find("const");
if (pos!=std::string::npos)
tmp.erase(pos,strlen("const"));
while ((pos=tmp.find(' '))!=std::string::npos){
tmp.erase(pos,1);
}
return addType(Class,tmp);
}
std::cerr<<"Unhandled type name"<<tname<<std::endl;
return NULL;
}
const std::string &getName()const{
return mName;
}
BasicType getBasicType()const{
return mBasic;
}
private:
BasicType mBasic;
std::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 Type sArrayType;
static std::map<std::string,Type*> mTypes;
};
class Argument{
public:
Argument(Type *type, const std::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 std::string &getName()const{
return mName;
}
bool isPointer()const{
return mPointer;
}
const std::string &getHelp()const{
return mHelp;
}
void setHelp(const std::string &help){
mHelp=help;
}
private:
Type *mType;
std::string mName;
std::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, bool isCallback=false){
mUid=uid;
mReturn=return_arg;
mName=name;
mArgs=args;
mConst=isConst;
mStatic=isStatic;
mIsCallback=isCallback;
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;
}
bool isCallback()const{
return mIsCallback;
}
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("is")==0 && mArgs.size()==0){
mPropertyName=mName.substr(2,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]);
mPropertyName+="Enabled";
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()){
mPropertyName+="Enabled";
mPropertyBehaviour=Read;
}
}
}
if (mPropertyBehaviour==None) {
mPropertyName="";
if (mName.find("create")==0) {
mName="new"+mName.substr(6,string::npos);
}
}
}
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;
bool mIsCallback;
};
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;
};
class ConstField{
public:
ConstField(Type *type, const string &name, int value) : mType(type), mName(name), mValue(value){
}
void setHelp(const string & help){
mHelp=help;
}
const string &getHelp()const{
return mHelp;
}
const string & getName()const{
return mName;
}
Type *getType()const{
return mType;
}
int getValue()const{
return mValue;
}
static string getCommonPrefix(list<ConstField *> fields){
if (fields.size()<2) return "";
list<ConstField*>::iterator it;
string prefix=fields.front()->getName();
int prefixsize;
for (prefixsize=prefix.size();prefixsize>0;prefixsize--){
bool isMatching=true;
prefix=prefix.substr(0,prefixsize);
for(it=fields.begin();it!=fields.end();++it){
ConstField *cf=*it;
if (prefix != cf->getName().substr(0,prefixsize)){
isMatching=false;
break;
}
}
if (isMatching){
//cout<<"enum prefix: "<<prefix<<endl;
return prefix;
}
}
return "";
}
private:
Type *mType;
string mName;
int mValue;
string mHelp;
};
template <typename _type>
struct name_matcher{
name_matcher(const string &name) : mName(name){}
bool operator()(_type *cf){
return cf->getName()==mName;
}
string mName;
};
/*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 addConstField(ConstField *field){
list<ConstField*>::iterator it=find_if(mConstFields.begin(),mConstFields.end(),name_matcher<ConstField>(field->getName()));
if (it==mConstFields.end())
mConstFields.push_back(field);
}
void setHelp(const std::string &help){
mHelp=help;
}
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 list<ConstField*> &getConstFields()const{
return mConstFields;
}
const string &getName()const{
return mName;
}
const string &getHelp()const{
return mHelp;
}
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;
list<ConstField*> mConstFields;
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));
}
void addCallback(Method *callback){
list<Method*>::iterator it=find_if(mCallbacks.begin(),mCallbacks.end(),name_matcher<Method>(callback->getName()));
if (it==mCallbacks.end())
mCallbacks.push_back(callback);
}
const list<Method*> &getCallbacks()const{
return mCallbacks;
}
private:
map<string,Class*> mClasses;
list<Method*> mCallbacks;
string mName;
};
#endif