1. more C++ parser fixes - now it almost parses wx/string.h
a) #if/#ifdef/#else (very) limited support b) param type fix - now indirection chars are correctly handled c) class/struct/union distinction d) public/private fixes e) Dump() function added - very useful for debugging 2. option to ignore parameter names during 'diff' (in fact, they're ignored by default, and this option switches it on) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1744 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -38,6 +38,13 @@
|
||||
|
||||
#include "markup.h" // markup tags used in spOperator::GetFullName()
|
||||
|
||||
// these methods are used for debugging only and disappear in the release build
|
||||
#ifdef __WXDEBUG__
|
||||
#define DECLARE_DUMP virtual void DumpThis(const wxString& indent) const;
|
||||
#else
|
||||
#define DECLARE_DUMP
|
||||
#endif
|
||||
|
||||
// context class list in "inside-out" order :
|
||||
|
||||
class spContext;
|
||||
@@ -63,6 +70,7 @@ enum SRC_VISIBLITY_TYPES
|
||||
// class types
|
||||
enum SP_CLASS_TYPES
|
||||
{
|
||||
SP_CLTYPE_INVALID,
|
||||
SP_CLTYPE_CLASS,
|
||||
SP_CLTYPE_TEMPLATE_CLASS,
|
||||
SP_CLTYPE_STRUCTURE,
|
||||
@@ -445,11 +453,18 @@ public:
|
||||
|
||||
// each new context should override this method
|
||||
// to return it's specific type
|
||||
virtual int GetContextType() { return SP_CTX_UNKNOWN; }
|
||||
virtual int GetContextType() const { return SP_CTX_UNKNOWN; }
|
||||
|
||||
// perhaps more intuitive short-cut
|
||||
inline int GetType() { return GetContextType(); }
|
||||
|
||||
// cast this context to the desired type - returns NULL if type is wrong
|
||||
spAttribute *CastToAttribute()
|
||||
{
|
||||
return GetContextType() == SP_CTX_ATTRIBUTE ? (spAttribute *)this
|
||||
: NULL;
|
||||
}
|
||||
|
||||
// derived classes override this to invoke VisitXXX method
|
||||
// which corresponds to the class of specific context,
|
||||
// - this is what the "Visitor" pattern told us ^)
|
||||
@@ -468,6 +483,12 @@ public:
|
||||
void RemoveChildren();
|
||||
|
||||
spContext* GetEnclosingContext( int mask = SP_CTX_ANY );
|
||||
|
||||
#ifdef __WXDEBUG__
|
||||
virtual void Dump(const wxString& indent) const;
|
||||
#endif // __WXDEBUG__
|
||||
|
||||
DECLARE_DUMP
|
||||
};
|
||||
|
||||
// stores information about single argument of operation
|
||||
@@ -482,10 +503,12 @@ public:
|
||||
string mInitVal;
|
||||
|
||||
public:
|
||||
virtual int GetContextType() { return SP_CTX_PARAMETER; }
|
||||
virtual int GetContextType() const { return SP_CTX_PARAMETER; }
|
||||
|
||||
virtual void AcceptVisitor( spVisitor& visitor )
|
||||
{ visitor.VisitParameter( *this ); }
|
||||
|
||||
DECLARE_DUMP
|
||||
};
|
||||
|
||||
|
||||
@@ -504,10 +527,12 @@ public:
|
||||
bool mIsConstant;
|
||||
public:
|
||||
|
||||
virtual int GetContextType() { return SP_CTX_ATTRIBUTE; }
|
||||
virtual int GetContextType() const { return SP_CTX_ATTRIBUTE; }
|
||||
|
||||
virtual void AcceptVisitor( spVisitor& visitor )
|
||||
{ visitor.VisitAttribute( *this ); }
|
||||
|
||||
DECLARE_DUMP
|
||||
};
|
||||
|
||||
class spOperation : public spContext
|
||||
@@ -554,11 +579,12 @@ public:
|
||||
|
||||
virtual string GetFullName(MarkupTagsT tags);
|
||||
|
||||
virtual int GetContextType() { return SP_CTX_OPERATION; }
|
||||
virtual int GetContextType() const { return SP_CTX_OPERATION; }
|
||||
|
||||
virtual void AcceptVisitor( spVisitor& visitor )
|
||||
{ visitor.VisitOperation( *this ); }
|
||||
|
||||
DECLARE_DUMP
|
||||
};
|
||||
|
||||
// stores infromation about preprocessor directive
|
||||
@@ -576,14 +602,16 @@ public:
|
||||
|
||||
public:
|
||||
|
||||
virtual int GetContextType() { return SP_CTX_PREPROCESSOR; }
|
||||
virtual int GetContextType() const { return SP_CTX_PREPROCESSOR; }
|
||||
|
||||
virtual int GetStatementType() { return mDefType; }
|
||||
virtual int GetStatementType() const { return mDefType; }
|
||||
|
||||
string CPP_GetIncludedFileNeme();
|
||||
string CPP_GetIncludedFileNeme() const;
|
||||
|
||||
virtual void AcceptVisitor( spVisitor& visitor )
|
||||
{ visitor.VisitPreprocessorLine( *this ); }
|
||||
|
||||
DECLARE_DUMP
|
||||
};
|
||||
|
||||
// stores information about the class
|
||||
@@ -607,7 +635,6 @@ public:
|
||||
bool mIsAbstract;
|
||||
|
||||
public:
|
||||
|
||||
// sorts class members in the following order:
|
||||
//
|
||||
// (by "privacy level" - first private, than protected, public)
|
||||
@@ -622,10 +649,12 @@ public:
|
||||
|
||||
virtual void SortMembers();
|
||||
|
||||
virtual int GetContextType() { return SP_CTX_CLASS; }
|
||||
virtual int GetContextType() const { return SP_CTX_CLASS; }
|
||||
|
||||
virtual void AcceptVisitor( spVisitor& visitor )
|
||||
{ visitor.VisitClass( *this ); }
|
||||
|
||||
DECLARE_DUMP
|
||||
};
|
||||
|
||||
// stores information about enum statement
|
||||
@@ -636,10 +665,12 @@ public:
|
||||
string mEnumContent; // full-text content of enumeration
|
||||
|
||||
public:
|
||||
virtual int GetContextType() { return SP_CTX_ENUMERATION; }
|
||||
virtual int GetContextType() const { return SP_CTX_ENUMERATION; }
|
||||
|
||||
virtual void AcceptVisitor( spVisitor& visitor )
|
||||
{ visitor.VisitEnumeration( *this ); }
|
||||
|
||||
DECLARE_DUMP
|
||||
};
|
||||
|
||||
class spTypeDef : public spContext
|
||||
@@ -650,10 +681,12 @@ public:
|
||||
string mOriginalType;
|
||||
|
||||
public:
|
||||
virtual int GetContextType() { return SP_CTX_TYPEDEF; }
|
||||
virtual int GetContextType() const { return SP_CTX_TYPEDEF; }
|
||||
|
||||
virtual void AcceptVisitor( spVisitor& visitor )
|
||||
{ visitor.VisitTypeDef( *this ); }
|
||||
|
||||
DECLARE_DUMP
|
||||
};
|
||||
|
||||
// NOTE:: files context may be put to other
|
||||
@@ -668,10 +701,12 @@ public:
|
||||
string mFileName;
|
||||
|
||||
public:
|
||||
virtual int GetContextType() { return SP_CTX_FILE; }
|
||||
virtual int GetContextType() const { return SP_CTX_FILE; }
|
||||
|
||||
virtual void AcceptVisitor( spVisitor& visitor )
|
||||
{ visitor.VisitFile( *this ); }
|
||||
|
||||
DECLARE_DUMP
|
||||
};
|
||||
|
||||
//TODO:: comments.
|
||||
|
@@ -33,6 +33,7 @@
|
||||
(ii) plans for version 2
|
||||
1. Use wxTextFile for direct file access to avoid one scan method problems
|
||||
2. Use command line parser class for the options
|
||||
3. support for overloaded functions in diff mode (search for OVER)
|
||||
|
||||
(iii) plans for version 3
|
||||
1. Merging with existing files
|
||||
@@ -120,15 +121,70 @@ private:
|
||||
wxTeXFile& operator=(const wxTeXFile&);
|
||||
};
|
||||
|
||||
// helper class which manages the classes and function names to ignore for
|
||||
// the documentation purposes (used by both HelpGenVisitor and DocManager)
|
||||
class IgnoreNamesHandler
|
||||
{
|
||||
public:
|
||||
IgnoreNamesHandler() : m_ignore(CompareIgnoreListEntries) { }
|
||||
~IgnoreNamesHandler() { WX_CLEAR_ARRAY(m_ignore); }
|
||||
|
||||
// load file with classes/functions to ignore (add them to the names we
|
||||
// already have)
|
||||
bool AddNamesFromFile(const wxString& filename);
|
||||
|
||||
// return TRUE if we ignore this function
|
||||
bool IgnoreMethod(const wxString& classname,
|
||||
const wxString& funcname) const
|
||||
{
|
||||
if ( IgnoreClass(classname) )
|
||||
return TRUE;
|
||||
|
||||
IgnoreListEntry ignore(classname, funcname);
|
||||
|
||||
return m_ignore.Index(&ignore) != wxNOT_FOUND;
|
||||
}
|
||||
|
||||
// return TRUE if we ignore this class entirely
|
||||
bool IgnoreClass(const wxString& classname) const
|
||||
{
|
||||
IgnoreListEntry ignore(classname, "");
|
||||
|
||||
return m_ignore.Index(&ignore) != wxNOT_FOUND;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct IgnoreListEntry
|
||||
{
|
||||
IgnoreListEntry(const wxString& classname,
|
||||
const wxString& funcname)
|
||||
: m_classname(classname), m_funcname(funcname)
|
||||
{
|
||||
}
|
||||
|
||||
wxString m_classname;
|
||||
wxString m_funcname; // if empty, ignore class entirely
|
||||
};
|
||||
|
||||
static int CompareIgnoreListEntries(IgnoreListEntry *first,
|
||||
IgnoreListEntry *second);
|
||||
|
||||
// for efficiency, let's sort it
|
||||
WX_DEFINE_SORTED_ARRAY(IgnoreListEntry *, ArrayNamesToIgnore);
|
||||
|
||||
ArrayNamesToIgnore m_ignore;
|
||||
|
||||
private:
|
||||
IgnoreNamesHandler(const IgnoreNamesHandler&);
|
||||
IgnoreNamesHandler& operator=(const IgnoreNamesHandler&);
|
||||
};
|
||||
|
||||
// visitor implementation which writes all collected data to a .tex file
|
||||
class HelpGenVisitor : public spVisitor
|
||||
{
|
||||
public:
|
||||
// ctor
|
||||
HelpGenVisitor(const wxString& directoryOut) : m_directoryOut(directoryOut)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
HelpGenVisitor(const wxString& directoryOut, bool overwrite);
|
||||
|
||||
virtual void VisitFile( spFile& fl );
|
||||
virtual void VisitClass( spClass& cl );
|
||||
@@ -141,6 +197,9 @@ public:
|
||||
|
||||
void EndVisit();
|
||||
|
||||
// get our `ignore' object
|
||||
IgnoreNamesHandler& GetIgnoreHandler() { return m_ignoreNames; }
|
||||
|
||||
// shut up g++ warning (ain't it stupid?)
|
||||
virtual ~HelpGenVisitor() { }
|
||||
|
||||
@@ -160,7 +219,9 @@ protected:
|
||||
// terminate the function documentation if it was started
|
||||
void CloseFunction();
|
||||
|
||||
wxString m_directoryOut; // directory for the output
|
||||
wxString m_directoryOut, // directory for the output
|
||||
m_fileHeader; // name of the .h file we parse
|
||||
bool m_overwrite; // overwrite existing files?
|
||||
wxTeXFile m_file; // file we're writing to now
|
||||
|
||||
// state variables
|
||||
@@ -178,6 +239,10 @@ protected:
|
||||
// headers included by this file
|
||||
wxArrayString m_headers;
|
||||
|
||||
// ignore handler: tells us which classes to ignore for doc generation
|
||||
// purposes
|
||||
IgnoreNamesHandler m_ignoreNames;
|
||||
|
||||
private:
|
||||
HelpGenVisitor(const HelpGenVisitor&);
|
||||
HelpGenVisitor& operator=(const HelpGenVisitor&);
|
||||
@@ -189,18 +254,18 @@ private:
|
||||
class DocManager
|
||||
{
|
||||
public:
|
||||
DocManager() : m_ignore(CompareIgnoreListEntries) { }
|
||||
DocManager(bool checkParamNames);
|
||||
~DocManager();
|
||||
|
||||
// load file with class names and function names to ignore during diff
|
||||
bool LoadIgnoreFile(const wxString& filename);
|
||||
|
||||
// returns FALSE on failure
|
||||
bool ParseTeXFile(const wxString& filename);
|
||||
|
||||
// returns FALSE if there were any differences
|
||||
bool DumpDifferences(spContext *ctxTop) const;
|
||||
|
||||
// get our `ignore' object
|
||||
IgnoreNamesHandler& GetIgnoreHandler() { return m_ignoreNames; }
|
||||
|
||||
protected:
|
||||
// parsing TeX files
|
||||
// -----------------
|
||||
@@ -242,40 +307,8 @@ protected:
|
||||
|
||||
// functions and classes to ignore during diff
|
||||
// -------------------------------------------
|
||||
struct IgnoreListEntry
|
||||
{
|
||||
IgnoreListEntry(const wxString& classname,
|
||||
const wxString& funcname)
|
||||
: m_classname(classname), m_funcname(funcname)
|
||||
{
|
||||
}
|
||||
|
||||
wxString m_classname;
|
||||
wxString m_funcname; // if empty, ignore class entirely
|
||||
};
|
||||
|
||||
static int CompareIgnoreListEntries(IgnoreListEntry *first,
|
||||
IgnoreListEntry *second);
|
||||
|
||||
// for efficiency, let's sort it
|
||||
WX_DEFINE_SORTED_ARRAY(IgnoreListEntry *, ArrayNamesToIgnore);
|
||||
|
||||
ArrayNamesToIgnore m_ignore;
|
||||
|
||||
// return TRUE if we ignore this function
|
||||
bool IgnoreMethod(const wxString& classname,
|
||||
const wxString& funcname) const
|
||||
{
|
||||
IgnoreListEntry ignore(classname, funcname);
|
||||
|
||||
return m_ignore.Index(&ignore) != wxNOT_FOUND;
|
||||
}
|
||||
|
||||
// return TRUE if we ignore this class entirely
|
||||
bool IgnoreClass(const wxString& classname) const
|
||||
{
|
||||
return IgnoreMethod(classname, "");
|
||||
}
|
||||
IgnoreNamesHandler m_ignoreNames;
|
||||
|
||||
// information about all functions documented in the TeX file(s)
|
||||
// -------------------------------------------------------------
|
||||
@@ -367,6 +400,13 @@ protected:
|
||||
// the class name appears in m_classes
|
||||
wxArrayString m_classes;
|
||||
ArrayMethodInfos m_methods;
|
||||
|
||||
// are we checking parameter names?
|
||||
bool m_checkParamNames;
|
||||
|
||||
private:
|
||||
DocManager(const DocManager&);
|
||||
DocManager& operator=(const DocManager&);
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -397,18 +437,20 @@ static void usage()
|
||||
" -v be verbose\n"
|
||||
" -H give this usage message\n"
|
||||
" -V print the version info\n"
|
||||
" -i file file with classes/function to ignore\n"
|
||||
"\n"
|
||||
" where mode is one of: dump, diff\n"
|
||||
"\n"
|
||||
" dump means generate .tex files for TeX2RTF converter from specified\n"
|
||||
" headers files, mode options are:\n"
|
||||
" -f overwrite existing files\n"
|
||||
" -o outdir directory for generated files\n"
|
||||
"\n"
|
||||
" diff means compare the set of methods documented .tex file with the\n"
|
||||
" methods declared in the header:\n"
|
||||
" %s diff <file.h> <files.tex...>.\n"
|
||||
" options are:\n"
|
||||
" -i file file with classes/function to ignore during diff\n"
|
||||
" mode specific options are:\n"
|
||||
" -p do check parameter names (not done by default)\n"
|
||||
"\n", basename.c_str(), basename.c_str());
|
||||
|
||||
exit(1);
|
||||
@@ -430,7 +472,10 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
wxArrayString filesH, filesTeX;
|
||||
wxString directoryOut, ignoreFile;
|
||||
wxString directoryOut, // directory for 'dmup' output
|
||||
ignoreFile; // file with classes/functions to ignore
|
||||
bool overwrite = FALSE, // overwrite existing files during 'dump'?
|
||||
paramNames = FALSE; // check param names during 'diff'?
|
||||
|
||||
for ( int current = 1; current < argc ; current++ ) {
|
||||
// all options have one letter
|
||||
@@ -452,12 +497,6 @@ int main(int argc, char **argv)
|
||||
usage();
|
||||
|
||||
case 'i':
|
||||
if ( mode != Mode_Diff ) {
|
||||
wxLogError("-i is only valid with diff.");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
current++;
|
||||
if ( current >= argc ) {
|
||||
wxLogError("-i option requires an argument.");
|
||||
@@ -468,6 +507,26 @@ int main(int argc, char **argv)
|
||||
ignoreFile = argv[current];
|
||||
continue;
|
||||
|
||||
case 'p':
|
||||
if ( mode != Mode_Diff ) {
|
||||
wxLogError("-p is only valid with diff.");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
paramNames = TRUE;
|
||||
continue;
|
||||
|
||||
case 'f':
|
||||
if ( mode != Mode_Dump ) {
|
||||
wxLogError("-f is only valid with dump.");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
overwrite = TRUE;
|
||||
continue;
|
||||
|
||||
case 'o':
|
||||
if ( mode != Mode_Dump ) {
|
||||
wxLogError("-o is only valid with dump.");
|
||||
@@ -501,12 +560,16 @@ int main(int argc, char **argv)
|
||||
continue;
|
||||
|
||||
default:
|
||||
wxLogError("unknown option '%s'", argv[current]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
wxLogError("only one letter options are allowed, not '%s'.",
|
||||
argv[current]);
|
||||
}
|
||||
|
||||
// only get here after a break from switch or from else branch of if
|
||||
wxLogError("unknown option '%s'", argv[current]);
|
||||
|
||||
usage();
|
||||
}
|
||||
@@ -517,7 +580,7 @@ int main(int argc, char **argv)
|
||||
else if ( strcmp(argv[current], "dump") == 0 )
|
||||
mode = Mode_Dump;
|
||||
else {
|
||||
wxLogError("unknown mode '%s'.");
|
||||
wxLogError("unknown mode '%s'.", argv[current]);
|
||||
|
||||
usage();
|
||||
}
|
||||
@@ -538,7 +601,10 @@ int main(int argc, char **argv)
|
||||
|
||||
// create a parser object and a visitor derivation
|
||||
CJSourceParser parser;
|
||||
HelpGenVisitor visitor(directoryOut);
|
||||
HelpGenVisitor visitor(directoryOut, overwrite);
|
||||
if ( !!ignoreFile && mode == Mode_Dump )
|
||||
visitor.GetIgnoreHandler().AddNamesFromFile(ignoreFile);
|
||||
|
||||
spContext *ctxTop = NULL;
|
||||
|
||||
// parse all header files
|
||||
@@ -555,6 +621,11 @@ int main(int argc, char **argv)
|
||||
visitor.VisitAll(*ctxTop);
|
||||
visitor.EndVisit();
|
||||
}
|
||||
|
||||
#ifdef __WXDEBUG__
|
||||
if ( 0 && ctxTop )
|
||||
ctxTop->Dump("");
|
||||
#endif // __WXDEBUG__
|
||||
}
|
||||
|
||||
// parse all TeX files
|
||||
@@ -566,7 +637,7 @@ int main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
DocManager docman;
|
||||
DocManager docman(paramNames);
|
||||
|
||||
size_t nFiles = filesTeX.GetCount();
|
||||
for ( size_t n = 0; n < nFiles; n++ ) {
|
||||
@@ -578,7 +649,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if ( !!ignoreFile )
|
||||
docman.LoadIgnoreFile(ignoreFile);
|
||||
docman.GetIgnoreHandler().AddNamesFromFile(ignoreFile);
|
||||
|
||||
docman.DumpDifferences(ctxTop);
|
||||
}
|
||||
@@ -590,6 +661,15 @@ int main(int argc, char **argv)
|
||||
// HelpGenVisitor implementation
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
HelpGenVisitor::HelpGenVisitor(const wxString& directoryOut,
|
||||
bool overwrite)
|
||||
: m_directoryOut(directoryOut)
|
||||
{
|
||||
m_overwrite = overwrite;
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
void HelpGenVisitor::Reset()
|
||||
{
|
||||
m_inClass =
|
||||
@@ -657,20 +737,31 @@ void HelpGenVisitor::EndVisit()
|
||||
{
|
||||
CloseFunction();
|
||||
|
||||
m_fileHeader.Empty();
|
||||
|
||||
wxLogVerbose("%s: finished generating for the current file.",
|
||||
GetCurrentTime("%H:%M:%S"));
|
||||
}
|
||||
|
||||
void HelpGenVisitor::VisitFile( spFile& file )
|
||||
{
|
||||
m_fileHeader = file.mFileName;
|
||||
wxLogVerbose("%s: started generating docs for classes from file '%s'...",
|
||||
GetCurrentTime("%H:%M:%S"), file.mFileName.c_str());
|
||||
GetCurrentTime("%H:%M:%S"), m_fileHeader.c_str());
|
||||
}
|
||||
|
||||
void HelpGenVisitor::VisitClass( spClass& cl )
|
||||
{
|
||||
m_inClass = FALSE; // will be left FALSE on error
|
||||
|
||||
wxString name = cl.GetName();
|
||||
|
||||
if ( m_ignoreNames.IgnoreClass(name) ) {
|
||||
wxLogVerbose("Skipping ignored class '%s'.", name.c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// the file name is built from the class name by removing the leading "wx"
|
||||
// if any and converting it to the lower case
|
||||
wxString filename = m_directoryOut;
|
||||
@@ -684,12 +775,10 @@ void HelpGenVisitor::VisitClass( spClass& cl )
|
||||
filename.MakeLower();
|
||||
filename += ".tex";
|
||||
|
||||
if ( wxFile::Exists(filename) ) {
|
||||
wxLogError("Won't overwrite existing file '%s' - please use '-o'.",
|
||||
if ( !m_overwrite && wxFile::Exists(filename) ) {
|
||||
wxLogError("Won't overwrite existing file '%s' - please use '-f'.",
|
||||
filename.c_str());
|
||||
|
||||
m_inClass = FALSE;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -720,7 +809,7 @@ void HelpGenVisitor::VisitClass( spClass& cl )
|
||||
"\n"
|
||||
"\n"
|
||||
"\\section{\\class{%s}}\\label{%s}\n",
|
||||
filename.c_str(), GetCurrentTime("%d/%b/%y %H:%M:%S"),
|
||||
m_fileHeader.c_str(), GetCurrentTime("%d/%b/%y %H:%M:%S"),
|
||||
name.c_str(), wxString(name).MakeLower().c_str());
|
||||
|
||||
totalText << header << '\n';
|
||||
@@ -931,8 +1020,14 @@ void HelpGenVisitor::VisitOperation( spOperation& op )
|
||||
{
|
||||
CloseFunction();
|
||||
|
||||
if ( !m_inClass || !op.IsInClass() ) {
|
||||
// FIXME that's a bug too
|
||||
if ( !m_inClass ) {
|
||||
// we don't generate docs right now - either we ignore this class
|
||||
// entirely or we couldn't open the file
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !op.IsInClass() ) {
|
||||
// TODO document global functions
|
||||
wxLogWarning("skipped global function '%s'.", op.GetName().c_str());
|
||||
|
||||
return;
|
||||
@@ -943,6 +1038,15 @@ void HelpGenVisitor::VisitOperation( spOperation& op )
|
||||
return;
|
||||
}
|
||||
|
||||
wxString funcname = op.GetName(),
|
||||
classname = op.GetClass().GetName();
|
||||
if ( m_ignoreNames.IgnoreMethod(classname, funcname) ) {
|
||||
wxLogVerbose("Skipping ignored '%s::%s'.",
|
||||
classname.c_str(), funcname.c_str());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
InsertMethodsHeader();
|
||||
|
||||
// save state info
|
||||
@@ -953,13 +1057,11 @@ void HelpGenVisitor::VisitOperation( spOperation& op )
|
||||
|
||||
// start function documentation
|
||||
wxString totalText;
|
||||
const char *funcname = op.GetName().c_str();
|
||||
const char *classname = op.GetClass().GetName().c_str();
|
||||
|
||||
// check for the special case of dtor
|
||||
wxString dtor;
|
||||
if ( (funcname[0] == '~') && (strcmp(funcname + 1, classname) == 0) ) {
|
||||
dtor.Printf("\\destruct{%s}", classname);
|
||||
if ( (funcname[0] == '~') && (classname == funcname.c_str() + 1) ) {
|
||||
dtor.Printf("\\destruct{%s}", classname.c_str());
|
||||
funcname = dtor;
|
||||
}
|
||||
|
||||
@@ -967,12 +1069,12 @@ void HelpGenVisitor::VisitOperation( spOperation& op )
|
||||
"\\membersection{%s::%s}\\label{%s}\n"
|
||||
"\n"
|
||||
"\\%sfunc{%s%s}{%s}{",
|
||||
classname, funcname,
|
||||
classname.c_str(), funcname.c_str(),
|
||||
MakeLabel(classname, funcname).c_str(),
|
||||
op.mIsConstant ? "const" : "",
|
||||
op.mIsVirtual ? "virtual " : "",
|
||||
op.mRetType.c_str(),
|
||||
funcname);
|
||||
funcname.c_str());
|
||||
|
||||
m_file.WriteTeX(totalText);
|
||||
}
|
||||
@@ -1005,6 +1107,11 @@ void HelpGenVisitor::VisitParameter( spParameter& param )
|
||||
// DocManager
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
DocManager::DocManager(bool checkParamNames)
|
||||
{
|
||||
m_checkParamNames = checkParamNames;
|
||||
}
|
||||
|
||||
size_t DocManager::TryMatch(const char *str, const char *match)
|
||||
{
|
||||
size_t lenMatch = 0;
|
||||
@@ -1280,7 +1387,7 @@ bool DocManager::ParseTeXFile(const wxString& filename)
|
||||
lenMatch = TryMatch(current, "void");
|
||||
if ( !lenMatch ) {
|
||||
lenMatch = TryMatch(current, "param");
|
||||
while ( lenMatch ) {
|
||||
while ( lenMatch && (current - buf < len) ) {
|
||||
current += lenMatch;
|
||||
|
||||
// now come {paramtype}{paramname}
|
||||
@@ -1423,7 +1530,7 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const
|
||||
const wxString& nameClass = ctxClass->mName;
|
||||
int index = m_classes.Index(nameClass);
|
||||
if ( index == wxNOT_FOUND ) {
|
||||
if ( !IgnoreClass(nameClass) ) {
|
||||
if ( !m_ignoreNames.IgnoreClass(nameClass) ) {
|
||||
foundDiff = TRUE;
|
||||
|
||||
wxLogError("Class '%s' is not documented at all.",
|
||||
@@ -1466,7 +1573,7 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const
|
||||
}
|
||||
|
||||
if ( aMethodsWithSameName.IsEmpty() && ctxMethod->IsPublic() ) {
|
||||
if ( !IgnoreMethod(nameClass, nameMethod) ) {
|
||||
if ( !m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) {
|
||||
foundDiff = TRUE;
|
||||
|
||||
wxLogError("'%s::%s' is not documented.",
|
||||
@@ -1481,7 +1588,7 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const
|
||||
index = (size_t)aMethodsWithSameName[0u];
|
||||
methodExists[index] = TRUE;
|
||||
|
||||
if ( IgnoreMethod(nameClass, nameMethod) )
|
||||
if ( m_ignoreNames.IgnoreMethod(nameClass, nameMethod) )
|
||||
continue;
|
||||
|
||||
if ( !ctxMethod->IsPublic() ) {
|
||||
@@ -1533,7 +1640,8 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const
|
||||
|
||||
spParameter *ctxParam = (spParameter *)ctx;
|
||||
const ParamInfo& param = method.GetParam(nParam);
|
||||
if ( param.GetName() != ctxParam->mName ) {
|
||||
if ( m_checkParamNames &&
|
||||
(param.GetName() != ctxParam->mName) ) {
|
||||
foundDiff = TRUE;
|
||||
|
||||
wxLogError("Parameter #%d of '%s::%s' should be "
|
||||
@@ -1575,9 +1683,9 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO add real support for overloaded methods
|
||||
// TODO OVER add real support for overloaded methods
|
||||
|
||||
if ( IgnoreMethod(nameClass, nameMethod) )
|
||||
if ( m_ignoreNames.IgnoreMethod(nameClass, nameMethod) )
|
||||
continue;
|
||||
|
||||
if ( aOverloadedMethods.Index(nameMethod) == wxNOT_FOUND ) {
|
||||
@@ -1602,7 +1710,7 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const
|
||||
for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
|
||||
if ( !methodExists[nMethod] ) {
|
||||
const wxString& nameMethod = methods[nMethod]->GetName();
|
||||
if ( !IgnoreMethod(nameClass, nameMethod) ) {
|
||||
if ( !m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) {
|
||||
foundDiff = TRUE;
|
||||
|
||||
wxLogError("'%s::%s' is documented but doesn't exist.",
|
||||
@@ -1633,10 +1741,13 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const
|
||||
DocManager::~DocManager()
|
||||
{
|
||||
WX_CLEAR_ARRAY(m_methods);
|
||||
WX_CLEAR_ARRAY(m_ignore);
|
||||
}
|
||||
|
||||
int DocManager::CompareIgnoreListEntries(IgnoreListEntry *first,
|
||||
// ---------------------------------------------------------------------------
|
||||
// IgnoreNamesHandler implementation
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry *first,
|
||||
IgnoreListEntry *second)
|
||||
{
|
||||
// first compare the classes
|
||||
@@ -1647,7 +1758,7 @@ int DocManager::CompareIgnoreListEntries(IgnoreListEntry *first,
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool DocManager::LoadIgnoreFile(const wxString& filename)
|
||||
bool IgnoreNamesHandler::AddNamesFromFile(const wxString& filename)
|
||||
{
|
||||
wxFile file(filename, wxFile::read);
|
||||
if ( !file.IsOpened() )
|
||||
@@ -1803,11 +1914,52 @@ static const char *GetCurrentTime(const char *timeFormat)
|
||||
|
||||
/*
|
||||
$Log$
|
||||
Revision 1.7 1999/02/21 22:32:32 VZ
|
||||
1. more C++ parser fixes - now it almost parses wx/string.h
|
||||
a) #if/#ifdef/#else (very) limited support
|
||||
b) param type fix - now indirection chars are correctly handled
|
||||
c) class/struct/union distinction
|
||||
d) public/private fixes
|
||||
e) Dump() function added - very useful for debugging
|
||||
|
||||
2. option to ignore parameter names during 'diff' (in fact, they're ignored
|
||||
by default, and this option switches it on)
|
||||
|
||||
Revision 1.6 1999/02/20 23:00:26 VZ
|
||||
1. new 'diff' mode which seems to work
|
||||
2. output files are not overwritten in 'dmup' mode
|
||||
3. fixes for better handling of const functions and operators
|
||||
----------------------------
|
||||
revision 1.5
|
||||
date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
|
||||
1. Parser improvements
|
||||
a) const and virtual methods are parsed correctly (not static yet)
|
||||
b) "const" which is part of the return type is not swallowed
|
||||
|
||||
2. HelpGen improvements: -o outputdir parameter added to the cmd line,
|
||||
"//---------" kind comments discarded now.
|
||||
----------------------------
|
||||
revision 1.4
|
||||
date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
|
||||
|
||||
some tweaks to HelpGen
|
||||
----------------------------
|
||||
revision 1.3
|
||||
date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
|
||||
|
||||
HelpGen starting to compile with VC++
|
||||
----------------------------
|
||||
revision 1.2
|
||||
date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
|
||||
|
||||
supports typedefs, generates "See also:" and adds "virtual " for virtual
|
||||
functions
|
||||
----------------------------
|
||||
revision 1.1
|
||||
date: 1999/01/08 17:45:55; author: VZ; state: Exp;
|
||||
|
||||
HelpGen is a prototype of the tool for automatic generation of the .tex files
|
||||
for wxWindows documentation from C++ headers
|
||||
*/
|
||||
|
||||
/* vi: set tw=80 et ts=4 sw=4: */
|
||||
|
@@ -1317,16 +1317,55 @@ void CJSourceParser::AddMacroNode( char*& cur )
|
||||
pPL->mDefType = SP_PREP_DEF_REDEFINE_SYMBOL;
|
||||
}
|
||||
}
|
||||
else
|
||||
if ( *start == 'i' )
|
||||
|
||||
else if ( *start == 'i' )
|
||||
{
|
||||
if ( cmp_tokens_fast( start, "include", 7 ) )
|
||||
{
|
||||
pPL->mDefType = SP_PREP_DEF_INCLUDE_FILE;
|
||||
}
|
||||
else if ( *++start == 'f' )
|
||||
{
|
||||
// either "#if" or "#ifdef"
|
||||
cur = start;
|
||||
skip_token( cur );
|
||||
get_next_token( cur );
|
||||
|
||||
string condition = get_token_str( cur );
|
||||
|
||||
// currently, everything except '0' is true
|
||||
if ( condition == "0" ) {
|
||||
// skip until the following else or enif
|
||||
while ( cur < _gSrcEnd ) {
|
||||
skip_to_eol( cur );
|
||||
skip_eol( cur );
|
||||
|
||||
get_next_token( cur );
|
||||
if ( *cur++ == '#' && *cur == 'e' )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO parse the condition...
|
||||
}
|
||||
}
|
||||
else if ( cmp_tokens_fast( start, "else", 4 ) )
|
||||
{
|
||||
// skip until "#endif"
|
||||
while ( cur < _gSrcEnd ) {
|
||||
skip_to_eol( cur );
|
||||
skip_eol( cur );
|
||||
|
||||
get_next_token( cur );
|
||||
if ( *cur++ == '#' && cmp_tokens_fast( cur, "endif", 5 ) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mpCurCtx->AddMember( pPL );
|
||||
|
||||
skip_to_eol( cur );
|
||||
skip_eol( cur );
|
||||
|
||||
restore_line_no( tmpLnNo );
|
||||
|
||||
clear_commets_queue();
|
||||
@@ -1537,6 +1576,8 @@ bool CJSourceParser::ParseNameAndRetVal( char*& cur, bool& isAMacro )
|
||||
pOp->mSrcLineNo = lineNo;
|
||||
pOp->mSrcOffset = int( start - _gSrcStart );
|
||||
pOp->mHeaderLength = int( bracketPos - start );
|
||||
if ( mpCurCtx->GetContextType() == SP_CTX_CLASS )
|
||||
pOp->mScope = mpCurCtx->mName;
|
||||
|
||||
mpCurCtx->AddMember( pOp );
|
||||
pOp->mVisibility = mCurVis;
|
||||
@@ -1552,31 +1593,38 @@ bool CJSourceParser::ParseNameAndRetVal( char*& cur, bool& isAMacro )
|
||||
|
||||
// checker whether it's not an operator
|
||||
char chFirst = *pOp->mName.c_str();
|
||||
if ( !isalpha(chFirst) && chFirst != '_' && chFirst != '~' )
|
||||
{
|
||||
if ( !isalpha(chFirst) && chFirst != '_' && chFirst != '~' ) {
|
||||
// skip 'operator'
|
||||
skip_next_token_back( cur );
|
||||
skip_token_back( cur );
|
||||
|
||||
string lastToken = get_token_str( cur );
|
||||
if ( lastToken == "operator" )
|
||||
{
|
||||
if ( lastToken == "operator" ) {
|
||||
lastToken += pOp->mName;
|
||||
pOp->mName = lastToken;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
// ok, it wasn't an operator after all
|
||||
skip_token( cur );
|
||||
}
|
||||
}
|
||||
else if ( pOp->mName == "operator" ) {
|
||||
skip_token( cur );
|
||||
get_next_token( cur );
|
||||
string oper = get_token_str( cur );
|
||||
|
||||
pOp->mName += oper;
|
||||
}
|
||||
|
||||
// go backwards to method return type
|
||||
skip_next_token_back( cur );
|
||||
|
||||
if ( cur >= start )
|
||||
|
||||
pOp->mRetType = string( start, size_t( cur-start ) );
|
||||
{
|
||||
string rettype = string( start, size_t( cur-start ) );
|
||||
rettype.Replace("WXDLLEXPORT ", ""); // FIXME just for now...
|
||||
pOp->mRetType = rettype;
|
||||
}
|
||||
|
||||
arrange_indirection_tokens_between( pOp->mRetType, pOp->mName );
|
||||
|
||||
@@ -1704,7 +1752,7 @@ bool CJSourceParser::ParseArguments( char*& cur )
|
||||
|
||||
pPar->mType = string( blocks[0], len );
|
||||
|
||||
arrange_indirection_tokens_between( pPar->mType, pOp->mName );
|
||||
arrange_indirection_tokens_between( pPar->mType, pPar->mName );
|
||||
|
||||
if ( *cur == ')' )
|
||||
{
|
||||
@@ -1857,17 +1905,21 @@ void CJSourceParser::ParseMemberVar( char*& cur )
|
||||
|
||||
} while(1);
|
||||
|
||||
first = 0;
|
||||
|
||||
// set up types for all collected (same-type) attributes;
|
||||
while ( first != members.size() - 1 )
|
||||
{
|
||||
spAttribute* pAttr = (spAttribute*)members[first];
|
||||
spAttribute* pAttr = members[first++]->CastToAttribute();
|
||||
if ( !pAttr )
|
||||
continue;
|
||||
|
||||
if ( !pAttr->mType )
|
||||
pAttr->mType = type;
|
||||
pAttr->mVisibility = mCurVis;
|
||||
|
||||
if ( !!pAttr->mName )
|
||||
arrange_indirection_tokens_between( pAttr->mType, pAttr->mName );
|
||||
|
||||
++first;
|
||||
}
|
||||
|
||||
cur = savedPos;
|
||||
@@ -1975,6 +2027,8 @@ void CJSourceParser::AddClassNode( char*& cur )
|
||||
{
|
||||
char* ctxStart = cur;
|
||||
|
||||
string classkeyword = get_token_str( cur );
|
||||
|
||||
skip_token( cur ); // skip 'class' keyword
|
||||
if ( !get_next_token( cur ) ) return;
|
||||
|
||||
@@ -1985,14 +2039,32 @@ void CJSourceParser::AddClassNode( char*& cur )
|
||||
get_next_token( cur );
|
||||
}
|
||||
|
||||
spClass* pClass = new spClass();
|
||||
|
||||
|
||||
mpCurCtx->AddMember( pClass );
|
||||
|
||||
// by default all class members are private
|
||||
mCurVis = SP_VIS_PRIVATE;
|
||||
|
||||
spClass* pClass = new spClass();
|
||||
if ( classkeyword == "class" )
|
||||
pClass->mClassSubType = SP_CLTYPE_CLASS;
|
||||
else if ( classkeyword == "struct" ) {
|
||||
pClass->mClassSubType = SP_CLTYPE_STRUCTURE;
|
||||
|
||||
mCurVis = SP_VIS_PUBLIC;
|
||||
}
|
||||
else if ( classkeyword == "union" ) {
|
||||
pClass->mClassSubType = SP_CLTYPE_UNION;
|
||||
|
||||
mCurVis = SP_VIS_PUBLIC;
|
||||
}
|
||||
else if ( classkeyword == "interface" )
|
||||
pClass->mClassSubType = SP_CLTYPE_INTERFACE;
|
||||
else {
|
||||
pClass->mClassSubType = SP_CLTYPE_INVALID;
|
||||
|
||||
wxFAIL_MSG("unknown class keyword");
|
||||
}
|
||||
|
||||
mpCurCtx->AddMember( pClass );
|
||||
|
||||
// attach comments about the class
|
||||
AttachComments( *pClass, cur );
|
||||
|
||||
|
@@ -238,7 +238,7 @@ inline void ScriptTemplate::PrintVar( TVarInfo* pInfo,
|
||||
if ( !sz )
|
||||
{
|
||||
// DBG::
|
||||
int u;
|
||||
int u = 0;
|
||||
++u;
|
||||
break;
|
||||
}
|
||||
|
@@ -472,7 +472,7 @@ string spOperation::GetFullName(MarkupTagsT tags)
|
||||
|
||||
/***** Implemenentation for class spPreprocessorLine *****/
|
||||
|
||||
string spPreprocessorLine::CPP_GetIncludedFileNeme()
|
||||
string spPreprocessorLine::CPP_GetIncludedFileNeme() const
|
||||
{
|
||||
wxASSERT( GetStatementType() == SP_PREP_DEF_INCLUDE_FILE );
|
||||
|
||||
@@ -545,3 +545,164 @@ void SourceParserBase::SetPlugin( SourceParserPlugin* pPlugin )
|
||||
|
||||
mpPlugin = pPlugin;
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// debug methods
|
||||
// ===========================================================================
|
||||
|
||||
#ifdef __WXDEBUG__
|
||||
|
||||
void spContext::Dump(const wxString& indent) const
|
||||
{
|
||||
DumpThis(indent);
|
||||
|
||||
// increase it for the children
|
||||
wxString indentChild = indent + " ";
|
||||
|
||||
for ( MMemberListT::const_iterator i = mMembers.begin();
|
||||
i != mMembers.end();
|
||||
i++ ) {
|
||||
(*i)->Dump(indentChild);
|
||||
}
|
||||
}
|
||||
|
||||
void spContext::DumpThis(const wxString& indent) const
|
||||
{
|
||||
wxFAIL_MSG("abstract base class can't be found in parser tree!");
|
||||
}
|
||||
|
||||
void spParameter::DumpThis(const wxString& indent) const
|
||||
{
|
||||
wxLogDebug("%sparam named '%s' of type '%s'",
|
||||
indent.c_str(), mName.c_str(), mType.c_str());
|
||||
}
|
||||
|
||||
void spAttribute::DumpThis(const wxString& indent) const
|
||||
{
|
||||
wxLogDebug("%svariable named '%s' of type '%s'",
|
||||
indent.c_str(), mName.c_str(), mType.c_str());
|
||||
}
|
||||
|
||||
void spOperation::DumpThis(const wxString& indent) const
|
||||
{
|
||||
wxString protection;
|
||||
if ( !!mScope ) {
|
||||
switch ( mVisibility ) {
|
||||
case SP_VIS_PUBLIC:
|
||||
protection = "public";
|
||||
break;
|
||||
|
||||
case SP_VIS_PROTECTED:
|
||||
protection = "protected";
|
||||
break;
|
||||
|
||||
case SP_VIS_PRIVATE:
|
||||
protection = "private";
|
||||
break;
|
||||
|
||||
default:
|
||||
wxFAIL_MSG("unknown protection type");
|
||||
}
|
||||
}
|
||||
else {
|
||||
protection = "global";
|
||||
}
|
||||
|
||||
wxLogDebug("%s%s%s%s function named '%s::%s' of type '%s'",
|
||||
indent.c_str(),
|
||||
mIsConstant ? "const " : "",
|
||||
mIsVirtual ? "virtual " : "",
|
||||
protection.c_str(),
|
||||
mScope.c_str(), mName.c_str(), mRetType.c_str());
|
||||
}
|
||||
|
||||
void spPreprocessorLine::DumpThis(const wxString& indent) const
|
||||
{
|
||||
wxString kind;
|
||||
switch ( mDefType ) {
|
||||
case SP_PREP_DEF_DEFINE_SYMBOL:
|
||||
kind = "define";
|
||||
break;
|
||||
|
||||
case SP_PREP_DEF_REDEFINE_SYMBOL:
|
||||
kind = "redefine";
|
||||
break;
|
||||
|
||||
case SP_PREP_DEF_INCLUDE_FILE:
|
||||
kind.Printf("include (%s)", CPP_GetIncludedFileNeme().c_str());
|
||||
break;
|
||||
|
||||
case SP_PREP_DEF_OTHER:
|
||||
kind = "other";
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
wxLogDebug("%spreprocessor statement: %s",
|
||||
indent.c_str(), kind.c_str());
|
||||
}
|
||||
|
||||
void spClass::DumpThis(const wxString& indent) const
|
||||
{
|
||||
wxString base;
|
||||
for ( StrListT::const_iterator i = mSuperClassNames.begin();
|
||||
i != mSuperClassNames.end();
|
||||
i++ ) {
|
||||
if ( !!base )
|
||||
base += ", ";
|
||||
base += *i;
|
||||
}
|
||||
|
||||
if ( !base )
|
||||
base = "none";
|
||||
|
||||
wxString kind;
|
||||
switch ( mClassSubType ) {
|
||||
case SP_CLTYPE_CLASS:
|
||||
kind = "class";
|
||||
break;
|
||||
|
||||
case SP_CLTYPE_TEMPLATE_CLASS:
|
||||
kind = "template class";
|
||||
break;
|
||||
|
||||
case SP_CLTYPE_STRUCTURE:
|
||||
kind = "struc";
|
||||
break;
|
||||
|
||||
case SP_CLTYPE_UNION:
|
||||
kind = "union";
|
||||
break;
|
||||
|
||||
case SP_CLTYPE_INTERFACE:
|
||||
kind = "interface";
|
||||
break;
|
||||
|
||||
default:
|
||||
wxFAIL_MSG("unknown class subtype");
|
||||
}
|
||||
|
||||
wxLogDebug("%s%s named '%s' (base classes: %s)",
|
||||
indent.c_str(), kind.c_str(),
|
||||
mName.c_str(), base.c_str());
|
||||
}
|
||||
|
||||
void spEnumeration::DumpThis(const wxString& indent) const
|
||||
{
|
||||
wxLogDebug("%senum named '%s'",
|
||||
indent.c_str(), mName.c_str());
|
||||
}
|
||||
|
||||
void spTypeDef::DumpThis(const wxString& indent) const
|
||||
{
|
||||
wxLogDebug("%stypedef %s = %s",
|
||||
indent.c_str(), mName.c_str(), mOriginalType.c_str());
|
||||
}
|
||||
|
||||
void spFile::DumpThis(const wxString& indent) const
|
||||
{
|
||||
wxLogDebug("%sfile '%s'",
|
||||
indent.c_str(), mFileName.c_str());
|
||||
}
|
||||
|
||||
#endif // __WXDEBUG__
|
||||
|
Reference in New Issue
Block a user