1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Parser of the API/interface XML files
4 // Author: Francesco Montorsi
7 // Copyright: (c) 2008 Francesco Montorsi
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx/wx.h".
12 #include "wx/wxprec.h"
18 // for all others, include the necessary headers
22 #include "wx/xml/xml.h"
23 #include "wx/wfstream.h"
24 #include "wx/arrimpl.cpp"
25 #include "wx/dynarray.h"
26 #include "wx/filename.h"
27 #include "xmlparser.h"
29 #define PROGRESS_RATE 1000 // each PROGRESS_RATE nodes processed print a dot
30 #define ESTIMATED_NUM_CLASSES 600 // used by both wxXmlInterface-derived classes to prealloc mem
31 #define ESTIMATED_NUM_TYPES 50000 // used only by wxGccXmlInterface to prealloc mem
32 #define ESTIMATED_NUM_FILES 800 // used only by wxGccXmlInterface to prealloc mem
34 WX_DEFINE_OBJARRAY(wxTypeArray
)
35 WX_DEFINE_OBJARRAY(wxMethodArray
)
36 WX_DEFINE_OBJARRAY(wxClassArray
)
39 // declared in ifacecheck.cpp
40 extern bool g_verbose
;
44 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
50 void wxType::SetFromString(const wxString
& t
)
52 m_strType
= t
.Strip(wxString::both
);
54 // [] is the same as * for gccxml
55 m_strType
.Replace("[]", "*");
58 bool wxType::IsOk() const
60 // NB: m_strType can contain the :: operator; think to e.g. the
61 // "reverse_iterator_impl<wxString::const_iterator>" type
62 // It can also contain commas, * and & operators etc
64 return !GetClean().IsEmpty();
67 wxString
wxType::GetClean() const
69 wxString
ret(m_strType
);
70 ret
.Replace("const", "");
71 ret
.Replace("static", "");
74 ret
.Replace("[]", "");
75 return ret
.Strip(wxString::both
);
78 bool wxType::operator==(const wxType
& m
) const
80 // brain-dead comparison:
82 if (GetClean() == m
.GetClean() &&
83 IsConst() == m
.IsConst() &&
84 IsStatic() == m
.IsStatic() &&
85 IsPointer() == m
.IsPointer() &&
86 IsReference() == m
.IsReference())
92 // ----------------------------------------------------------------------------
94 // ----------------------------------------------------------------------------
96 bool wxMethod::IsOk() const
98 // NOTE: m_retType can be a wxEmptyType, and means that this method
99 // is a ctor or a dtor.
100 if (!m_retType
.IsOk() && m_retType
!=wxEmptyType
) {
101 LogError("'%s' method has invalid return type: %s", m_retType
.GetAsString());
105 if (m_strName
.IsEmpty())
108 // a function can't be both const and static or virtual and static!
109 if ((m_bConst
&& m_bStatic
) || (m_bVirtual
&& m_bStatic
)) {
110 LogError("'%s' method can't be both const/static or virtual/static", m_strName
);
114 for (unsigned int i
=0; i
<m_args
.GetCount(); i
++)
115 if (!m_args
[i
].IsOk()) {
116 LogError("'%s' method has invalid %d-th argument type: %s",
117 m_strName
, i
, m_args
[i
].GetAsString());
121 // NB: the default value of the arguments can contain pretty much everything
122 // (think to e.g. wxPoint(3+4/2,0) or *wxBLACK or someClass<type>)
123 // so we don't do any test on them.
128 void wxMethod::SetArgumentTypes(const wxTypeArray
& arr
, const wxArrayString
& defaults
)
130 wxASSERT(arr
.GetCount()==defaults
.GetCount());
133 m_argDefaults
=defaults
;
135 // in order to make valid&simple comparison on argument defaults,
136 // we reduce some of the multiple forms in which the same things may appear
138 for (unsigned int i
=0; i
<m_argDefaults
.GetCount(); i
++)
140 m_argDefaults
[i
].Replace("NULL", "0");
141 m_argDefaults
[i
].Replace("0u", "0");
145 bool wxMethod::operator==(const wxMethod
& m
) const
147 if (GetReturnType() != m
.GetReturnType() ||
148 GetName() != m
.GetName() ||
149 IsConst() != m
.IsConst() ||
150 IsStatic() != m
.IsStatic() ||
151 IsVirtual() != m
.IsVirtual())
154 if (m_args
.GetCount()!=m
.m_args
.GetCount())
157 for (unsigned int i
=0; i
<m_args
.GetCount(); i
++)
158 if (m_args
[i
] != m
.m_args
[i
] || m_argDefaults
[i
] != m
.m_argDefaults
[i
])
164 wxString
wxMethod::GetAsString() const
168 if (m_retType
!=wxEmptyType
)
169 ret
+= m_retType
.GetAsString() + " ";
170 //else; this is a ctor or dtor
172 ret
+= m_strName
+ "(";
174 for (unsigned int i
=0; i
<m_args
.GetCount(); i
++)
176 ret
+= m_args
[i
].GetAsString();
177 if (!m_argDefaults
[i
].IsEmpty())
178 ret
+= " = " + m_argDefaults
[i
];
182 if (m_args
.GetCount()>0)
190 ret
= "static " + ret
;
192 ret
= "virtual " + ret
;
197 void wxMethod::Dump(wxTextOutputStream
& stream
) const
199 stream
<< "[" + m_retType
.GetAsString() + "]";
200 stream
<< "[" + m_strName
+ "]";
202 for (unsigned int i
=0; i
<m_args
.GetCount(); i
++)
203 stream
<< "[" + m_args
[i
].GetAsString() + "=" + m_argDefaults
[i
] + "]";
210 stream
<< " VIRTUAL";
215 // ----------------------------------------------------------------------------
217 // ----------------------------------------------------------------------------
219 wxString
wxClass::GetNameWithoutTemplate() const
221 // NB: I'm not sure this is the right terminology for this function!
223 if (m_strName
.Contains("<"))
224 return m_strName
.Left(m_strName
.Find("<"));
228 bool wxClass::IsValidCtorForThisClass(const wxMethod
& m
) const
230 // remember that e.g. the ctor for wxWritableCharTypeBuffer<wchar_t> is
231 // named wxWritableCharTypeBuffer, without the <...> part!
233 if (m
.IsCtor() && m
.GetName() == GetNameWithoutTemplate())
239 bool wxClass::IsValidDtorForThisClass(const wxMethod
& m
) const
241 if (m
.IsDtor() && m
.GetName() == "~" + GetNameWithoutTemplate())
247 void wxClass::Dump(wxTextOutputStream
& out
) const
249 out
<< m_strName
+ "\n";
251 for (unsigned int i
=0; i
<m_methods
.GetCount(); i
++) {
253 // dump all our methods
255 m_methods
[i
].Dump(out
);
262 bool wxClass::CheckConsistency() const
264 for (unsigned int i
=0; i
<m_methods
.GetCount(); i
++)
265 for (unsigned int j
=0; j
<m_methods
.GetCount(); j
++)
266 if (i
!=j
&& m_methods
[i
] == m_methods
[j
])
268 LogError("class %s has two methods with the same prototype: '%s'",
269 m_strName
, m_methods
[i
].GetAsString());
276 const wxMethod
* wxClass::FindMethod(const wxMethod
& m
) const
278 for (unsigned int i
=0; i
<m_methods
.GetCount(); i
++)
279 if (m_methods
[i
] == m
)
280 return &m_methods
[i
];
284 wxMethodPtrArray
wxClass::FindMethodNamed(const wxString
& name
) const
286 wxMethodPtrArray ret
;
288 for (unsigned int i
=0; i
<m_methods
.GetCount(); i
++)
289 if (m_methods
[i
].GetName() == name
)
290 ret
.Add(&m_methods
[i
]);
296 // ----------------------------------------------------------------------------
298 // ----------------------------------------------------------------------------
300 WX_DEFINE_SORTED_ARRAY(wxClass
*, wxSortedClassArray
);
302 int CompareWxClassObjects(wxClass
*item1
, wxClass
*item2
)
304 // sort alphabetically
305 return item1
->GetName().Cmp(item2
->GetName());
308 void wxXmlInterface::Dump(const wxString
& filename
)
310 wxFFileOutputStream
apioutput( filename
);
311 wxTextOutputStream
apiout( apioutput
);
313 // dump the classes in alphabetical order
314 wxSortedClassArray
sorted(CompareWxClassObjects
);
315 sorted
.Alloc(m_classes
.GetCount());
316 for (unsigned int i
=0; i
<m_classes
.GetCount(); i
++)
317 sorted
.Add(&m_classes
[i
]);
319 // now they have been sorted
320 for (unsigned int i
=0; i
<sorted
.GetCount(); i
++)
321 sorted
[i
]->Dump(apiout
);
324 bool wxXmlInterface::CheckParseResults() const
326 // this check can be quite slow, so do it only for debug releases:
328 for (unsigned int i
=0; i
<m_classes
.GetCount(); i
++)
329 if (!m_classes
[i
].CheckConsistency())
336 // ----------------------------------------------------------------------------
338 // ----------------------------------------------------------------------------
340 #define ATTRIB_CONST 1
341 #define ATTRIB_REFERENCE 2
342 #define ATTRIB_POINTER 4
343 #define ATTRIB_ARRAY 8
345 class toResolveTypeItem
348 toResolveTypeItem() { attribs
=0; }
349 toResolveTypeItem(const wxString
& namestr
, int attribint
)
350 : ref(namestr
), attribs(attribint
) {}
357 WX_DECLARE_STRING_HASH_MAP( toResolveTypeItem
, wxToResolveTypeHashMap
);
360 typedef std::map
<wxString
, toResolveTypeItem
> wxToResolveTypeHashMap
;
363 bool wxXmlGccInterface::Parse(const wxString
& filename
)
369 LogMessage("Parsing %s...", filename
);
371 if (!doc
.Load(filename
)) {
372 LogError("can't load %s", filename
);
376 // start processing the XML file
377 if (doc
.GetRoot()->GetName() != "GCC_XML") {
378 LogError("invalid root node for %s", filename
);
382 wxToResolveTypeHashMap toResolveTypes
;
383 wxArrayString arrMemberIds
;
384 wxStringHashMap types
;
385 wxStringHashMap files
;
387 // prealloc quite a lot of memory!
388 m_classes
.Alloc(ESTIMATED_NUM_CLASSES
);
389 arrMemberIds
.Alloc(ESTIMATED_NUM_TYPES
);
391 // build a list of wx classes and in general of all existent types
392 child
= doc
.GetRoot()->GetChildren();
395 const wxString
& n
= child
->GetName();
396 const wxString
& id
= child
->GetAttribute("id", wxEmptyString
);
400 wxString cname
= child
->GetAttribute("name", wxEmptyString
);
401 if (cname
.IsEmpty()) {
402 LogError("Invalid empty name for '%s' node", n
);
406 // only register wx classes (do remember also the IDs of their members)
407 if (cname
.StartsWith("wx")) {
408 arrMemberIds
.Add(child
->GetAttribute("members", wxEmptyString
));
410 // NB: "file" attribute contains an ID value that we'll resolve later
411 m_classes
.Add(wxClass(cname
, child
->GetAttribute("file", wxEmptyString
)));
414 // register this class also as possible return/argument type:
417 else if (n
== "PointerType" || n
== "ReferenceType" ||
418 n
== "CvQualifiedType" || n
== "ArrayType")
420 const wxString
& type
= child
->GetAttribute("type", wxEmptyString
);
421 if (id
.IsEmpty() || type
.IsEmpty()) {
422 LogError("Invalid empty type/id for '%s' node", n
);
427 if (n
== "PointerType")
428 attr
= ATTRIB_POINTER
;
429 else if (n
== "ReferenceType")
430 attr
= ATTRIB_REFERENCE
;
431 else if (n
== "CvQualifiedType" && child
->GetAttribute("const", "") == "1")
433 else if (n
== "ArrayType")
436 // these nodes make reference to other types... we'll resolve them later
437 toResolveTypes
[id
] = toResolveTypeItem(type
, attr
);
439 else if (n
== "FunctionType" || n
== "MethodType")
441 /* TODO: incomplete */
443 const wxString
& ret
= child
->GetAttribute("returns", wxEmptyString
);
444 if (id
.IsEmpty() || ret
.IsEmpty()) {
445 LogError("Invalid empty ret/id for '%s' node", n
);
449 // these nodes make reference to other types... we'll resolve them later
450 toResolveTypes
[id
] = toResolveTypeItem(ret
, 0);
452 else if (n
== "File")
454 if (!id
.StartsWith("f")) {
455 LogError("Unexpected file ID: %s", id
);
459 // just ignore this node... all file IDs/names were already parsed
460 files
[id
] = child
->GetAttribute("name", "");
464 // we register everything else as a possible return/argument type:
465 const wxString
& name
= child
->GetAttribute("name", wxEmptyString
);
470 //typeNames.Add(name);
475 // this may happen with unnamed structs/union, special ctors,
476 // or other exotic things which we are not interested to, since
477 // they're never used as return/argument types by wxWidgets methods
480 LogWarning("Type '%s' with ID '%s' does not have name attribute", n
, id
);
486 child
= child
->GetNext();
488 // give feedback to the user about the progress...
489 if ((++nodes%PROGRESS_RATE
)==0) ShowProgress();
492 // some nodes with IDs referenced by methods as return/argument types, do reference
493 // in turn o ther nodes (see PointerType, ReferenceType and CvQualifierType above);
494 // thus we need to resolve their name iteratively:
495 while (toResolveTypes
.size()>0)
498 LogMessage("%d types were collected; %d types need yet to be resolved...",
499 types
.size(), toResolveTypes
.size());
501 for (wxToResolveTypeHashMap::iterator i
= toResolveTypes
.begin();
502 i
!= toResolveTypes
.end();)
504 const wxString
& id
= i
->first
;
505 const wxString
& referenced
= i
->second
.ref
;
507 wxStringHashMap::iterator primary
= types
.find(referenced
);
508 if (primary
!= types
.end())
510 // this to-resolve-type references a "primary" type
513 int attribs
= i
->second
.attribs
;
515 if (attribs
& ATTRIB_CONST
)
516 newtype
= "const " + primary
->second
;
517 if (attribs
& ATTRIB_REFERENCE
)
518 newtype
= primary
->second
+ "&";
519 if (attribs
& ATTRIB_POINTER
)
520 newtype
= primary
->second
+ "*";
521 if (attribs
& ATTRIB_ARRAY
)
522 newtype
= primary
->second
+ "[]";
524 // add the resolved type to the list of "primary" types
527 // this one has been resolved; erase it through its iterator!
528 toResolveTypes
.erase(i
);
530 // now iterator i is invalid; assign it again to the beginning
531 i
= toResolveTypes
.begin();
535 // then search in the referenced types themselves:
536 wxToResolveTypeHashMap::iterator idx2
= toResolveTypes
.find(referenced
);
537 if (idx2
!= toResolveTypes
.end())
539 // merge this to-resolve-type with the idx2->second type
540 i
->second
.ref
= idx2
->second
.ref
;
541 i
->second
.attribs
|= idx2
->second
.attribs
;
543 // this type will eventually be solved in the next while() iteration
549 LogError("Cannot solve '%s' reference type!", referenced
);
552 typeIds
.Add(toResolveTypeIds
[i
]);
553 typeNames
.Add("TOFIX");
555 // this one has been resolved!
556 toResolveTypeIds
.RemoveAt(i
);
557 toResolveRefType
.RemoveAt(i
);
558 toResolveAttrib
.RemoveAt(i
);
566 // resolve header names
567 for (unsigned int i
=0; i
<m_classes
.GetCount(); i
++)
569 wxStringHashMap::const_iterator idx
= files
.find(m_classes
[i
].GetHeader());
570 if (idx
== files
.end())
573 LogError("couldn't find file ID '%s'", m_classes
[i
].GetHeader());
576 m_classes
[i
].SetHeader(idx
->second
);
579 // build the list of the wx methods
580 child
= doc
.GetRoot()->GetChildren();
583 wxString n
= child
->GetName();
585 if (n
== "Method" || n
== "Constructor" || n
== "Destructor" || n
== "OperatorMethod")
587 wxString id
= child
->GetAttribute("id", wxEmptyString
);
589 // only register public methods
590 if (child
->GetAttribute("access", wxEmptyString
) == "public")
592 wxASSERT(arrMemberIds
.GetCount()==m_classes
.GetCount());
594 for (unsigned int i
=0; i
<m_classes
.GetCount(); i
++)
596 if (arrMemberIds
[i
].Contains(id
))
598 // this <Method> node is a method of the i-th class!
600 if (!ParseMethod(child
, types
, newfunc
))
603 if (newfunc
.IsCtor() && !m_classes
[i
].IsValidCtorForThisClass(newfunc
)) {
604 LogError("The method '%s' does not seem to be a ctor for '%s'",
605 newfunc
.GetName(), m_classes
[i
].GetName());
608 if (newfunc
.IsDtor() && !m_classes
[i
].IsValidDtorForThisClass(newfunc
)) {
609 LogError("The method '%s' does not seem to be a dtor for '%s'",
610 newfunc
.GetName(), m_classes
[i
].GetName());
614 m_classes
[i
].AddMethod(newfunc
);
620 child
= child
->GetNext();
622 // give feedback to the user about the progress...
623 if ((++nodes%PROGRESS_RATE
)==0) ShowProgress();
627 if (!CheckParseResults())
633 bool wxXmlGccInterface::ParseMethod(const wxXmlNode
*p
,
634 const wxStringHashMap
& types
,
638 wxString name
= p
->GetAttribute("name", wxEmptyString
).Strip(wxString::both
);
639 if (p
->GetName() == "Destructor")
641 else if (p
->GetName() == "OperatorMethod")
642 name
= "operator" + name
;
644 // resolve return type
646 wxString retid
= p
->GetAttribute("returns", wxEmptyString
);
649 if (p
->GetName() != "Destructor" && p
->GetName() != "Constructor") {
650 LogError("Empty return ID for method '%s', with ID '%s'",
651 name
, p
->GetAttribute("id", ""));
657 wxStringHashMap::const_iterator retidx
= types
.find(retid
);
658 if (retidx
== types
.end()) {
659 LogError("Could not find return type ID '%s'", retid
);
663 ret
= wxType(retidx
->second
);
665 LogError("Invalid return type '%s' for method '%s', with ID '%s'",
666 retidx
->second
, name
, p
->GetAttribute("id", ""));
671 // resolve argument types
672 wxTypeArray argtypes
;
673 wxArrayString argdefs
;
674 wxXmlNode
*arg
= p
->GetChildren();
677 if (arg
->GetName() == "Argument")
679 wxString id
= arg
->GetAttribute("type", wxEmptyString
);
680 wxStringHashMap::const_iterator idx
= types
.find(id
);
681 if (idx
== types
.end()) {
682 LogError("Could not find argument type ID '%s'", id
);
686 argtypes
.Add(wxType(idx
->second
));
688 wxString def
= arg
->GetAttribute("default", "");
689 if (def
.Contains("wxGetTranslation"))
690 argdefs
.Add(wxEmptyString
); // TODO: wxGetTranslation gives problems to gccxml
695 arg
= arg
->GetNext();
698 m
.SetReturnType(ret
);
700 m
.SetArgumentTypes(argtypes
, argdefs
);
701 m
.SetConst(p
->GetAttribute("const", "") == "1");
702 m
.SetStatic(p
->GetAttribute("static", "") == "1");
703 m
.SetVirtual(p
->GetAttribute("virtual", "") == "1");
706 LogError("The prototype '%s' is not valid!", m
.GetAsString());
714 // ----------------------------------------------------------------------------
715 // wxXmlDoxygenInterface
716 // ----------------------------------------------------------------------------
718 bool wxXmlDoxygenInterface::Parse(const wxString
& filename
)
723 LogMessage("Parsing %s...", filename
);
725 if (!index
.Load(filename
)) {
726 LogError("can't load %s", filename
);
730 // start processing the index:
731 if (index
.GetRoot()->GetName() != "doxygenindex") {
732 LogError("invalid root node for %s", filename
);
736 m_classes
.Alloc(ESTIMATED_NUM_CLASSES
);
738 // process files referenced by this index file
739 compound
= index
.GetRoot()->GetChildren();
742 if (compound
->GetName() == "compound" &&
743 compound
->GetAttribute("kind", "") == "class")
745 wxString refid
= compound
->GetAttribute("refid", "");
747 wxFileName
fn(filename
);
748 if (!ParseCompoundDefinition(fn
.GetPath(wxPATH_GET_SEPARATOR
) + refid
+ ".xml"))
752 compound
= compound
->GetNext();
756 if (!CheckParseResults())
762 bool wxXmlDoxygenInterface::ParseCompoundDefinition(const wxString
& filename
)
769 LogMessage("Parsing %s...", filename
);
771 if (!doc
.Load(filename
)) {
772 LogError("can't load %s", filename
);
776 // start processing this compound definition XML
777 if (doc
.GetRoot()->GetName() != "doxygen") {
778 LogError("invalid root node for %s", filename
);
782 // build a list of wx classes
783 child
= doc
.GetRoot()->GetChildren();
786 if (child
->GetName() == "compounddef" &&
787 child
->GetAttribute("kind", wxEmptyString
) == "class")
791 wxString absoluteFile
, header
;
793 wxXmlNode
*subchild
= child
->GetChildren();
796 if (subchild
->GetName() == "sectiondef" &&
797 subchild
->GetAttribute("kind", wxEmptyString
) == "public-func")
800 wxXmlNode
*membernode
= subchild
->GetChildren();
803 if (membernode
->GetName() == "memberdef" &&
804 membernode
->GetAttribute("kind", wxEmptyString
) == "function")
808 if (ParseMethod(membernode
, m
, header
))
810 if (absoluteFile
.IsEmpty())
811 absoluteFile
= header
;
812 else if (header
!= absoluteFile
)
814 LogError("The method '%s' is documented in a different "
815 "file from others (which belong to '%s') ?",
816 header
, absoluteFile
);
824 membernode
= membernode
->GetNext();
827 // all methods of this class were taken from the header "absoluteFile":
828 klass
.SetHeader(absoluteFile
);
830 else if (subchild
->GetName() == "compoundname")
832 klass
.SetName(subchild
->GetNodeContent());
834 /*else if (subchild->GetName() == "includes")
836 // NOTE: we'll get the header from the <location> tags
837 // scattered inside <memberdef> tags instead of
838 // this <includes> tag since it does not contain
839 // the absolute path of the header
841 klass.SetHeader(subchild->GetNodeContent());
844 subchild
= subchild
->GetNext();
849 m_classes
.Add(klass
);
851 LogWarning("discarding class '%s' with %d methods...",
852 klass
.GetName(), klass
.GetMethodCount());
855 child
= child
->GetNext();
857 // give feedback to the user about the progress...
858 if ((++nodes%PROGRESS_RATE
)==0) ShowProgress();
864 static wxString
GetTextFromChildren(const wxXmlNode
*n
)
870 // <a><b>this</b> is a <b>string</b></a>
879 // unlike wxXmlNode::GetNodeContent() which would return " is a "
880 // this function returns "this is a string"
882 wxXmlNode
*ref
= n
->GetChildren();
884 if (ref
->GetType() == wxXML_ELEMENT_NODE
)
885 text
+= ref
->GetNodeContent();
886 else if (ref
->GetType() == wxXML_TEXT_NODE
)
887 text
+= ref
->GetContent();
889 LogWarning("Unexpected node type while getting text from '%s' node", n
->GetName());
891 ref
= ref
->GetNext();
897 bool wxXmlDoxygenInterface::ParseMethod(const wxXmlNode
* p
, wxMethod
& m
, wxString
& header
)
903 wxXmlNode
*child
= p
->GetChildren();
906 if (child
->GetName() == "name")
907 m
.SetName(child
->GetNodeContent());
908 else if (child
->GetName() == "type")
909 m
.SetReturnType(wxType(GetTextFromChildren(child
)));
910 else if (child
->GetName() == "param")
912 wxString typestr
, defstr
, arrstr
;
913 wxXmlNode
*n
= child
->GetChildren();
916 if (n
->GetName() == "type")
917 // if the <type> node has children, they should be all TEXT and <ref> nodes
918 // and we need to take the text they contain, in the order they appear
919 typestr
= GetTextFromChildren(n
);
920 else if (n
->GetName() == "defval")
921 // same for the <defval> node
922 defstr
= GetTextFromChildren(n
);
923 else if (n
->GetName() == "array")
924 arrstr
= GetTextFromChildren(n
);
929 if (typestr
.IsEmpty()) {
930 LogError("cannot find type node for a param in method '%s'", m
.GetName());
934 args
.Add(wxType(typestr
+ arrstr
));
937 else if (child
->GetName() == "location")
939 if (child
->GetAttribute("line", "").ToLong(&line
))
940 m
.SetLocation((int)line
);
941 header
= child
->GetAttribute("file", "");
944 child
= child
->GetNext();
947 m
.SetArgumentTypes(args
, defs
);
948 m
.SetConst(p
->GetAttribute("const", "")=="yes");
949 m
.SetStatic(p
->GetAttribute("static", "")=="yes");
950 m
.SetVirtual(p
->GetAttribute("virt", "")=="virtual");
953 LogError("The prototype '%s' is not valid!", m
.GetAsString());