Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
BC
public
liblinphone
Commits
c6a96174
Commit
c6a96174
authored
Sep 23, 2013
by
Simon Morlat
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
split genwrappers into several smaller pieces
parent
f8ead1fa
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
767 additions
and
620 deletions
+767
-620
oRTP
oRTP
+1
-1
tools/Makefile.am
tools/Makefile.am
+3
-1
tools/generator.cc
tools/generator.cc
+284
-0
tools/generator.hh
tools/generator.hh
+66
-0
tools/genwrappers.cc
tools/genwrappers.cc
+4
-618
tools/software-desc.cc
tools/software-desc.cc
+40
-0
tools/software-desc.hh
tools/software-desc.hh
+369
-0
No files found.
oRTP
@
ce8c1975
Subproject commit
706f0b59f818a69c673053e831fa1f19a855f80b
Subproject commit
ce8c19753495b4ad16a6c5df2bf2bf235443f762
tools/Makefile.am
View file @
c6a96174
...
...
@@ -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)
...
...
tools/generator.cc
0 → 100644
View file @
c6a96174
/*
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
;
}
tools/generator.hh
0 → 100644
View file @
c6a96174
/*
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
tools/genwrappers.cc
View file @
c6a96174
...
...
@@ -18,632 +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 <fstream>
#include <sstream>
#include <list>
#include <map>
#include <algorithm>
#include <sys/types.h>
#include <sys/stat.h>
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
;
};
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"
};
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
){