/* 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 #include #include #include #include #include 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 getChildren(const string &name)const{ xmlNode *it; list 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 "<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 "<getBasicType()<<" "<getName()<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< args; string help; XmlNode funcnode(node); XmlNode parameterlist; list params; list paramsHelp; list::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"<setHelp(item.getChild("parameterdescription").getChild("para").getText()); }else cerr<<"Undocumented parameter "<getName()<<" in function "<getType()->getBasicType()!=Type::Class) return; className=first_arg->getType()->getName(); methodName=extractMethodName(name,className); if (!methodName.empty() && methodName!="destroy"){ //cout<<"Found "<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 params=node.getChildRecursive("parameterlist").getChildren("parameteritem"); list::iterator it=params.begin(); string rettype=node.getChild("type").getText(); argsstring=argsstring.substr(argsstring.find('(')+1,string::npos); bool cont=true; list 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 && commasetHelp((*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 "<getName()<<" with "<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 enumValues=node.getChildren("enumvalue"); list::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"<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."< files; list::iterator it; LIBXML_TEST_VERSION for(i=1;i 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 !"<analyse(); gen->generate(proj); return 0; }