software-desc.hh 11 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
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

24
#include <functional>
25 26 27 28
#include <iostream>
#include <list>
#include <map>
#include <algorithm>
29
#include <string>
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

#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,
49 50
		Callback,
		Array
51 52 53 54 55 56 57 58 59 60 61 62 63
	};
	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){
64
		if (tname.find("(")!=string::npos) return NULL; //arrives when parsing function pointer declared inside function prototype
65 66
		if (strstr(tname.c_str(),"char")!=0 && strchr(tname.c_str(),'*')!=0){
			return &sStringType;
67
		}else if (tname.find("int")!=string::npos){
68
			return &sIntegerType;
69 70 71
		}else if (tname.find("size_t")!=string::npos){
			return &sIntegerType;
		}else if (tname.find("float")!=string::npos){
72
			return &sFloatType;
73
		}else if (tname.find("bool_t")!=string::npos){
74 75 76
			return &sBooleanType;
		}else if (tname.find("void")!=string::npos){
			return &sVoidType;
77
		}else if (tname.find("enum")!=string::npos){
78
			return addType(Enum,tname.c_str()+strlen("enum "));
79 80
		}else if (tname.find("MSList")!=string::npos){
			return &sArrayType;
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
		}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;
120
	static Type sArrayType;
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
	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
	};
165
	Method(const std::string &uid, Argument* return_arg, const std::string &name, const list<Argument*> &args, bool isConst, bool isStatic, bool isCallback=false){
166 167 168 169 170 171
		mUid=uid;
		mReturn=return_arg;
		mName=name;
		mArgs=args;
		mConst=isConst;
		mStatic=isStatic;
172
		mIsCallback=isCallback;
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
		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;
	}
193 194 195
	bool isCallback()const{
		return mIsCallback;
	}
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
	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()){
213 214 215 216 217 218
				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()){
219 220 221 222 223 224 225
				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]);
226
				mPropertyName+="Enabled";
227 228 229 230 231 232 233 234 235 236 237 238 239
				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()){
240
					mPropertyName+="Enabled";
241 242 243 244
					mPropertyBehaviour=Read;
				}
			}
		}
245
		if (mPropertyBehaviour==None) {
246
			mPropertyName="";
247 248 249 250
			if (mName.find("create")==0) {
				mName="new"+mName.substr(6,string::npos);
			}
		}
251 252 253 254 255 256 257 258 259 260
	}
	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;
261
	bool mIsCallback;
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
};

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

Simon Morlat's avatar
Simon Morlat committed
297 298
class ConstField{
public:
299
	ConstField(Type *type, const string &name, int value) : mType(type), mName(name), mValue(value){
Simon Morlat's avatar
Simon Morlat committed
300 301 302 303 304 305 306 307 308 309 310 311 312
	}
	void setHelp(const string & help){
		mHelp=help;
	}
	const string &getHelp()const{
		return mHelp;
	}
	const string & getName()const{
		return mName;
	}
	Type *getType()const{
		return mType;
	}
313
	int getValue()const{
Simon Morlat's avatar
Simon Morlat committed
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
		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){
334
				//cout<<"enum prefix: "<<prefix<<endl;
Simon Morlat's avatar
Simon Morlat committed
335 336 337 338 339 340 341 342
				return prefix;
			}
		}
		return "";
	}
private:
	Type *mType;
	string mName;
343
	int mValue;
Simon Morlat's avatar
Simon Morlat committed
344 345 346 347 348 349 350 351 352 353 354 355
	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;
};

356 357 358 359 360 361 362 363 364 365 366 367
/*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));
	}
Simon Morlat's avatar
Simon Morlat committed
368 369 370 371 372
	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);
	}
373 374 375
	void setHelp(const std::string &help){
		mHelp=help;
	}
Simon Morlat's avatar
Simon Morlat committed
376
	list<Method*> getMethods()const{
377 378 379 380 381 382 383
		list<Method*> ret;
		map<string,Method*>::const_iterator it;
		for(it=mMethods.begin();it!=mMethods.end();++it){
			ret.push_back((*it).second);
		}
		return ret;
	}
Simon Morlat's avatar
Simon Morlat committed
384 385 386
	const list<ConstField*> &getConstFields()const{
		return mConstFields;
	}
387 388 389 390 391 392
	const string &getName()const{
		return mName;
	}
	const string &getHelp()const{
		return mHelp;
	}
Simon Morlat's avatar
Simon Morlat committed
393
	list<Property*> getProperties(){
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
		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;
Simon Morlat's avatar
Simon Morlat committed
427
	list<ConstField*> mConstFields;
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
	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));
	}
458 459 460 461 462 463 464 465
	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;
	}
466 467
private:
	map<string,Class*> mClasses;
468
	list<Method*> mCallbacks;
469 470 471 472
	string mName;
};

#endif