(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
// wxWindows
#include "wx/wxprec.h"
+#if wxUSE_GUI
+ #error "This is a console program and can be only compiled using wxBase"
+#endif
+
#ifndef WX_PRECOMP
- #include <wx/string.h>
- #include <wx/log.h>
- #include <wx/dynarray.h>
+ #include "wx/string.h"
+ #include "wx/log.h"
+ #include "wx/dynarray.h"
+ #include "wx/wx.h"
#endif // WX_PRECOMP
-#include <wx/file.h>
+#include "wx/file.h"
+#include "wx/regex.h"
+#include "wx/hash.h"
// C++ parsing classes
#include "cjparser.h"
#include <stdio.h>
#include <time.h>
+// argh, Windows defines this
+#ifdef GetCurrentTime
+#undef GetCurrentTime
+#endif
+
// -----------------------------------------------------------------------------
// global vars
// -----------------------------------------------------------------------------
-// just a copy of argv
-static char **g_argv = NULL;
+class HelpGenApp: public wxApp
+{
+public:
+ HelpGenApp() {};
+
+ // don't let wxWin parse our cmd line, we do it ourselves
+ virtual bool OnInit() { return TRUE; }
+
+ virtual int OnRun();
+};
+
+// IMPLEMENT_APP(HelpGenApp);
// -----------------------------------------------------------------------------
// private functions
// get the string with current time (returns pointer to static buffer)
// timeFormat is used for the call of strftime(3)
-#ifdef GetCurrentTime
-#undef GetCurrentTime
-#endif
-
static const char *GetCurrentTime(const char *timeFormat);
+// get the string containing the program version
+static const wxString GetVersionString();
+
// -----------------------------------------------------------------------------
// private classes
// -----------------------------------------------------------------------------
-// add a function which sanitazes the string before writing it to the file
+// a function documentation entry
+struct FunctionDocEntry
+{
+ FunctionDocEntry(const wxString& name_, const wxString& text_)
+ : name(name_), text(text_) { }
+
+ // the function name
+ wxString name;
+
+ // the function doc text
+ wxString text;
+
+ // sorting stuff
+ static int Compare(FunctionDocEntry **pp1, FunctionDocEntry **pp2)
+ {
+ // the methods should appear in the following order: ctors, dtor, all
+ // the rest in the alphabetical order
+ bool isCtor1 = (*pp1)->name == classname;
+ bool isCtor2 = (*pp2)->name == classname;
+
+ if ( isCtor1 ) {
+ if ( isCtor2 ) {
+ // we don't order the ctors because we don't know how to do it
+ return 0;
+ }
+
+ // ctor comes before non-ctor
+ return -1;
+ }
+ else {
+ if ( isCtor2 ) {
+ // non-ctor must come after ctor
+ return 1;
+ }
+
+ wxString dtorname = wxString('~') + classname;
+
+ // there is only one dtor, so the logic here is simpler
+ if ( (*pp1)->name == dtorname ) {
+ return -1;
+ }
+ else if ( (*pp2)->name == dtorname ) {
+ return 1;
+ }
+
+ // two normal methods
+ return strcmp((*pp1)->name, (*pp2)->name);
+ }
+ }
+
+ static wxString classname;
+};
+
+wxString FunctionDocEntry::classname;
+
+WX_DECLARE_OBJARRAY(FunctionDocEntry, FunctionDocEntries);
+
+#include "wx/arrimpl.cpp"
+
+WX_DEFINE_OBJARRAY(FunctionDocEntries);
+
+// add a function which sanitazes the string before writing it to the file and
+// also capable of delaying output and sorting it before really writing it to
+// the file (done from FlushAll())
class wxTeXFile : public wxFile
{
public:
wxTeXFile() { }
- bool WriteTeX(const wxString& s)
+ // write a string to file verbatim (should only be used for the strings
+ // inside verbatim environment)
+ void WriteVerbatim(const wxString& s)
+ {
+ m_text += s;
+ }
+
+ // write a string quoting TeX specials in it
+ void WriteTeX(const wxString& s)
{
wxString t(s);
TeXFilter(&t);
- return wxFile::Write(t);
+ m_text += t;
+ }
+
+ // do write everything to file
+ bool FlushAll()
+ {
+ if ( m_text.empty() )
+ return TRUE;
+
+ if ( !Write(m_text) ) {
+ wxLogError("Failed to output generated documentation.");
+
+ return FALSE;
+ }
+
+ m_text.clear();
+
+ return TRUE;
}
private:
wxTeXFile(const wxTeXFile&);
wxTeXFile& operator=(const wxTeXFile&);
+
+ wxString m_text;
+};
+
+// 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
{
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 );
void EndVisit();
+ // get our `ignore' object
+ IgnoreNamesHandler& GetIgnoreHandler() { return m_ignoreNames; }
+
// shut up g++ warning (ain't it stupid?)
virtual ~HelpGenVisitor() { }
// terminate the function documentation if it was started
void CloseFunction();
- wxString m_directoryOut; // directory for the output
+ // write out all function docs when there are no more left in this class
+ // after sorting them in alphabetical order
+ void CloseClass();
+
+ 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
bool m_inClass, // TRUE after file successfully opened
m_inTypesSection, // enums & typedefs go there
m_inMethodSection, // functions go here
- m_isFirstParam, // first parameter of current function?
- m_inFunction; // we're parsing a function declaration
+ m_isFirstParam; // first parameter of current function?
+
+ // non empty while parsing a class
+ wxString m_classname;
+
+ // these are only non-empty while parsing a method:
+ wxString m_funcName, // the function name
+ m_textFunc; // the function doc text
+
+ // the array containing the documentation entries for the functions in the
+ // class currently being parsed
+ FunctionDocEntries m_arrayFuncDocs;
// holders for "saved" documentation
- wxString m_textStoredEnums,
- m_textStoredTypedefs,
+ wxString m_textStoredTypedefs,
m_textStoredFunctionComment;
+ // for enums we have to use an array as we can't intermix the normal text
+ // and the text inside verbatim environment
+ wxArrayString m_storedEnums,
+ m_storedEnumsVerb;
+
// 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&);
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
// -----------------
// 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)
// -------------------------------------------------------------
// the class name appears in m_classes
wxArrayString m_classes;
ArrayMethodInfos m_methods;
-};
-// -----------------------------------------------------------------------------
-// private functions
-// -----------------------------------------------------------------------------
+ // are we checking parameter names?
+ bool m_checkParamNames;
+
+private:
+ DocManager(const DocManager&);
+ DocManager& operator=(const DocManager&);
+};
// =============================================================================
// implementation
// this function never returns
static void usage()
{
- wxString prog = g_argv[0];
- wxString basename = prog.BeforeLast('/');
+ wxString prog = wxTheApp->argv[0];
+ wxString basename = prog.AfterLast('/');
#ifdef __WXMSW__
if ( !basename )
- basename = prog.BeforeLast('\\');
+ basename = prog.AfterLast('\\');
#endif
if ( !basename )
basename = prog;
- wxLogError(
+ wxLogMessage(
"usage: %s [global options] <mode> [mode options] <files...>\n"
"\n"
" where global options are:\n"
" -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);
}
-int main(int argc, char **argv)
+int HelpGenApp::OnRun()
{
enum
{
Mode_Diff
} mode = Mode_None;
- g_argv = argv;
-
if ( argc < 2 ) {
usage();
}
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
case 'H':
// help requested
usage();
+ // doesn't return
+
+ case 'V':
+ // version requested
+ wxLogMessage("HelpGen version %s\n"
+ "(c) 1999-2001 Vadim Zeitlin\n",
+ GetVersionString().c_str());
+ return 0;
case 'i':
+ current++;
+ if ( current >= argc ) {
+ wxLogError("-i option requires an argument.");
+
+ break;
+ }
+
+ ignoreFile = argv[current];
+ continue;
+
+ case 'p':
if ( mode != Mode_Diff ) {
- wxLogError("-i is only valid with diff.");
+ wxLogError("-p is only valid with diff.");
break;
}
- current++;
- if ( current >= argc ) {
- wxLogError("-i option requires an argument.");
+ paramNames = TRUE;
+ continue;
+
+ case 'f':
+ if ( mode != Mode_Dump ) {
+ wxLogError("-f is only valid with dump.");
break;
}
- ignoreFile = argv[current];
+ overwrite = TRUE;
continue;
case 'o':
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();
}
else if ( strcmp(argv[current], "dump") == 0 )
mode = Mode_Dump;
else {
- wxLogError("unknown mode '%s'.");
+ wxLogError("unknown mode '%s'.", argv[current]);
usage();
}
// 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
visitor.VisitAll(*ctxTop);
visitor.EndVisit();
}
+
+#ifdef __WXDEBUG__
+ if ( 0 && ctxTop )
+ ctxTop->Dump("");
+#endif // __WXDEBUG__
}
// parse all TeX files
wxLogError("Can't complete diff.");
// failure
- return 1;
+ return FALSE;
}
- DocManager docman;
+ DocManager docman(paramNames);
size_t nFiles = filesTeX.GetCount();
for ( size_t n = 0; n < nFiles; n++ ) {
}
if ( !!ignoreFile )
- docman.LoadIgnoreFile(ignoreFile);
+ docman.GetIgnoreHandler().AddNamesFromFile(ignoreFile);
docman.DumpDifferences(ctxTop);
}
return 0;
}
+int main(int argc, char **argv)
+{
+ wxInitializer initializer;
+ if ( !initializer )
+ {
+ fprintf(stderr, "Failed to initialize the wxWindows library, aborting.");
+
+ return -1;
+ }
+ HelpGenApp app;
+ app.argc = argc;
+ app.argv = argv;
+ return app.OnRun();
+}
+
// -----------------------------------------------------------------------------
// HelpGenVisitor implementation
// -----------------------------------------------------------------------------
+HelpGenVisitor::HelpGenVisitor(const wxString& directoryOut,
+ bool overwrite)
+ : m_directoryOut(directoryOut)
+{
+ m_overwrite = overwrite;
+
+ Reset();
+}
+
void HelpGenVisitor::Reset()
{
m_inClass =
- m_inFunction =
m_inTypesSection =
m_inMethodSection = FALSE;
+ m_classname =
+ m_funcName =
+ m_textFunc =
m_textStoredTypedefs =
- m_textStoredEnums =
m_textStoredFunctionComment = "";
+
+ m_arrayFuncDocs.Empty();
+
+ m_storedEnums.Empty();
+ m_storedEnumsVerb.Empty();
m_headers.Empty();
}
void HelpGenVisitor::InsertEnumDocs()
{
- m_file.WriteTeX(m_textStoredEnums);
- m_textStoredEnums.Empty();
+ size_t count = m_storedEnums.GetCount();
+ for ( size_t n = 0; n < count; n++ )
+ {
+ m_file.WriteTeX(m_storedEnums[n]);
+ m_file.WriteVerbatim(m_storedEnumsVerb[n] + '\n');
+ }
+
+ m_storedEnums.Empty();
+ m_storedEnumsVerb.Empty();
}
void HelpGenVisitor::InsertDataStructuresHeader()
if ( !m_inTypesSection ) {
m_inTypesSection = TRUE;
- m_file.WriteTeX("\\wxheading{Data structures}\n\n");
+ m_file.WriteVerbatim("\\wxheading{Data structures}\n\n");
}
}
if ( !m_inMethodSection ) {
m_inMethodSection = TRUE;
- m_file.WriteTeX( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
+ m_file.WriteVerbatim( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
}
}
void HelpGenVisitor::CloseFunction()
{
- if ( m_inFunction ) {
- m_inFunction = FALSE;
-
- wxString totalText;
+ if ( !m_funcName.empty() ) {
if ( m_isFirstParam ) {
// no params found
- totalText << "\\void";
+ m_textFunc << "\\void";
+ }
+
+ m_textFunc << "}\n\n";
+
+ if ( !m_textStoredFunctionComment.IsEmpty() ) {
+ m_textFunc << m_textStoredFunctionComment << '\n';
}
- totalText << "}\n\n";
+ m_arrayFuncDocs.Add(new FunctionDocEntry(m_funcName, m_textFunc));
+
+ m_funcName.clear();
+ }
+}
+
+void HelpGenVisitor::CloseClass()
+{
+ CloseFunction();
+
+ if ( m_inClass ) {
+ size_t count = m_arrayFuncDocs.GetCount();
+ if ( count ) {
+ size_t n;
+ FunctionDocEntry::classname = m_classname;
+
+ m_arrayFuncDocs.Sort(FunctionDocEntry::Compare);
+
+ // Now examine each first line and if it's been seen, cut it
+ // off (it's a duplicate \membersection)
+ wxHashTable membersections(wxKEY_STRING);
+
+ for ( n = 0; n < count; n++ )
+ {
+ wxString section(m_arrayFuncDocs[n].text);
+
+ // Strip leading whitespace
+ int pos = section.Find("\\membersection");
+ if (pos > -1)
+ {
+ section = section.Mid(pos);
+ }
+
+ wxString ms(section.BeforeFirst(wxT('\n')));
+ if (membersections.Get(ms))
+ {
+ m_arrayFuncDocs[n].text = section.AfterFirst(wxT('\n'));
+ }
+ else
+ {
+ membersections.Put(ms, & membersections);
+ }
+ }
+
+ for ( n = 0; n < count; n++ ) {
+ m_file.WriteTeX(m_arrayFuncDocs[n].text);
+ }
- if ( !m_textStoredFunctionComment.IsEmpty() )
- totalText << m_textStoredFunctionComment << '\n';
+ m_arrayFuncDocs.Empty();
+ }
- m_file.WriteTeX(totalText);
+ m_inClass = FALSE;
+ m_classname.clear();
}
+ m_file.FlushAll();
}
void HelpGenVisitor::EndVisit()
{
CloseFunction();
+ CloseClass();
+
+ m_fileHeader.Empty();
+
+ m_file.FlushAll();
+ if (m_file.IsOpened())
+ {
+ m_file.Flush();
+ m_file.Close();
+ }
+
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 )
{
+ CloseClass();
+
+ if (m_file.IsOpened())
+ {
+ m_file.Flush();
+ m_file.Close();
+ }
+
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;
+ wxString filename;
if ( name(0, 2) == "wx" ) {
filename << name.c_str() + 2;
}
filename.MakeLower();
filename += ".tex";
+ filename.Prepend(m_directoryOut);
- 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;
}
wxLogInfo("Created new file '%s' for class '%s'.",
filename.c_str(), name.c_str());
+ // write out the header
+ wxString header;
+ header.Printf("%%\n"
+ "%% automatically generated by HelpGen %s from\n"
+ "%% %s at %s\n"
+ "%%\n"
+ "\n"
+ "\n"
+ "\\section{\\class{%s}}\\label{%s}\n\n",
+ GetVersionString().c_str(),
+ m_fileHeader.c_str(),
+ GetCurrentTime("%d/%b/%y %H:%M:%S"),
+ name.c_str(),
+ wxString(name).MakeLower().c_str());
+
+ m_file.WriteVerbatim(header);
+
// the entire text we're writing to file
wxString totalText;
- // write out the header
- {
- wxString header;
- header.Printf("%%\n"
- "%% automatically generated by HelpGen from\n"
- "%% %s at %s\n"
- "%%\n"
- "\n"
- "\n"
- "\\section{\\class{%s}}\\label{%s}\n",
- filename.c_str(), GetCurrentTime("%d/%b/%y %H:%M:%S"),
- name.c_str(), wxString(name).MakeLower().c_str());
-
- totalText << header << '\n';
- }
-
// if the header includes other headers they must be related to it... try to
// automatically generate the "See also" clause
if ( !m_headers.IsEmpty() ) {
}
totalText << derived << "\n\n";
+ // include file section
+ wxString includeFile = "\\wxheading{Include files}\n\n";
+ includeFile << "<" << m_fileHeader << ">";
+
+ totalText << includeFile << "\n\n";
+
// write all this to file
m_file.WriteTeX(totalText);
InsertDataStructuresHeader();
InsertTypedefDocs();
InsertEnumDocs();
+
+ //m_file.Flush();
}
void HelpGenVisitor::VisitEnumeration( spEnumeration& en )
}
// simply copy the enum text in the docs
- wxString enumeration = GetAllComments(en);
- enumeration << "{\\small \\begin{verbatim}\n"
- << en.mEnumContent
- << "\n\\end{verbatim}}\n";
+ wxString enumeration = GetAllComments(en),
+ enumerationVerb;
+
+ enumerationVerb << "\\begin{verbatim}\n"
+ << en.mEnumContent
+ << "\n\\end{verbatim}\n";
// remember for later use if we're not inside a class yet
if ( !m_inClass ) {
- if ( !m_textStoredEnums.IsEmpty() ) {
- m_textStoredEnums << '\n';
- }
-
- m_textStoredEnums << enumeration;
+ m_storedEnums.Add(enumeration);
+ m_storedEnumsVerb.Add(enumerationVerb);
}
else {
// write the header for this section if not done yet
InsertDataStructuresHeader();
- enumeration << '\n';
m_file.WriteTeX(enumeration);
+ m_file.WriteVerbatim(enumerationVerb);
+ m_file.WriteVerbatim('\n');
}
}
{
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;
return;
}
+ m_classname = op.GetClass().GetName();
+ wxString funcname = op.GetName();
+
+ if ( m_ignoreNames.IgnoreMethod(m_classname, funcname) ) {
+ wxLogVerbose("Skipping ignored '%s::%s'.",
+ m_classname.c_str(), funcname.c_str());
+
+ return;
+ }
+
InsertMethodsHeader();
// save state info
- m_inFunction =
+ m_funcName = funcname;
m_isFirstParam = TRUE;
m_textStoredFunctionComment = GetAllComments(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] == '~') && (m_classname == funcname.c_str() + 1) ) {
+ dtor.Printf("\\destruct{%s}", m_classname.c_str());
funcname = dtor;
}
- totalText.Printf("\n"
- "\\membersection{%s::%s}\\label{%s}\n"
- "\n"
- "\\%sfunc{%s%s}{%s}{",
- classname, funcname,
- MakeLabel(classname, funcname).c_str(),
- op.mIsConstant ? "const" : "",
- op.mIsVirtual ? "virtual " : "",
- op.mRetType.c_str(),
- funcname);
-
- m_file.WriteTeX(totalText);
+ m_textFunc.Printf("\n"
+ "\\membersection{%s::%s}\\label{%s}\n",
+ m_classname.c_str(), funcname.c_str(),
+ MakeLabel(m_classname, funcname).c_str());
+
+ wxString func;
+ func.Printf("\n"
+ "\\%sfunc{%s%s}{%s}{",
+ op.mIsConstant ? "const" : "",
+ op.mIsVirtual ? "virtual " : "",
+ op.mRetType.c_str(),
+ funcname.c_str());
+ m_textFunc += func;
}
void HelpGenVisitor::VisitParameter( spParameter& param )
{
- if ( !m_inFunction )
+ if ( m_funcName.empty() )
return;
- wxString totalText;
if ( m_isFirstParam ) {
m_isFirstParam = FALSE;
}
else {
- totalText << ", ";
+ m_textFunc << ", ";
}
- totalText << "\\param{" << param.mType << " }{" << param.GetName();
+ m_textFunc << "\\param{" << param.mType << " }{" << param.GetName();
wxString defvalue = param.mInitVal;
if ( !defvalue.IsEmpty() ) {
- totalText << " = " << defvalue;
+ m_textFunc << " = " << defvalue;
}
- totalText << '}';
-
- m_file.WriteTeX(totalText);
+ m_textFunc << '}';
}
// ---------------------------------------------------------------------------
// DocManager
// ---------------------------------------------------------------------------
+DocManager::DocManager(bool checkParamNames)
+{
+ m_checkParamNames = checkParamNames;
+}
+
size_t DocManager::TryMatch(const char *str, const char *match)
{
size_t lenMatch = 0;
lenMatch = TryMatch(current, "void");
if ( !lenMatch ) {
lenMatch = TryMatch(current, "param");
- while ( lenMatch ) {
+ while ( lenMatch && (current - buf < len) ) {
current += lenMatch;
// now come {paramtype}{paramname}
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.",
}
if ( aMethodsWithSameName.IsEmpty() && ctxMethod->IsPublic() ) {
- if ( !IgnoreMethod(nameClass, nameMethod) ) {
+ if ( !m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) {
foundDiff = TRUE;
wxLogError("'%s::%s' is not documented.",
index = (size_t)aMethodsWithSameName[0u];
methodExists[index] = TRUE;
- if ( IgnoreMethod(nameClass, nameMethod) )
+ if ( m_ignoreNames.IgnoreMethod(nameClass, nameMethod) )
continue;
if ( !ctxMethod->IsPublic() ) {
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 "
}
}
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 ) {
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.",
DocManager::~DocManager()
{
WX_CLEAR_ARRAY(m_methods);
- WX_CLEAR_ARRAY(m_ignore);
}
-int DocManager::CompareIgnoreListEntries(IgnoreListEntry *first,
- IgnoreListEntry *second)
+// ---------------------------------------------------------------------------
+// IgnoreNamesHandler implementation
+// ---------------------------------------------------------------------------
+
+int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry *first,
+ IgnoreListEntry *second)
{
// first compare the classes
int rc = first->m_classname.Cmp(second->m_classname);
return rc;
}
-bool DocManager::LoadIgnoreFile(const wxString& filename)
+bool IgnoreNamesHandler::AddNamesFromFile(const wxString& filename)
{
wxFile file(filename, wxFile::read);
if ( !file.IsOpened() )
}
}
- if ( funcname )
- label << funcname;
+ if ( funcname ) {
+ // special treatment for operatorXXX() stuff because the C operators
+ // are not valid in LaTeX labels
+ wxString oper;
+ if ( wxString(funcname).StartsWith("operator", &oper) ) {
+ label << "operator";
+
+ static const struct
+ {
+ const char *oper;
+ const char *name;
+ } operatorNames[] =
+ {
+ { "=", "assign" },
+ { "==", "equal" },
+ };
+
+ size_t n;
+ for ( n = 0; n < WXSIZEOF(operatorNames); n++ ) {
+ if ( oper == operatorNames[n].oper ) {
+ label << operatorNames[n].name;
+
+ break;
+ }
+ }
+
+ if ( n == WXSIZEOF(operatorNames) ) {
+ wxLogWarning("unknown operator '%s' - making dummy label.",
+ oper.c_str());
+
+ label << "unknown";
+ }
+ }
+ else // simply use the func name
+ {
+ label << funcname;
+ }
+ }
label.MakeLower();
return helpref;
}
+static void TeXFilter(wxString* str)
+{
+ // TeX special which can be quoted (don't include backslash nor braces as
+ // we generate them
+ static wxRegEx reNonSpecialSpecials("[#$%&_]"),
+ reAccents("[~^]");
+
+ // just quote
+ reNonSpecialSpecials.ReplaceAll(str, "\\\\\\0");
+
+ // can't quote these ones as they produce accents when preceded by
+ // backslash, so put them inside verb
+ reAccents.ReplaceAll(str, "\\\\verb|\\0|");
+}
+
static void TeXUnfilter(wxString* str)
{
// FIXME may be done much more quickly
str->Trim(TRUE);
str->Trim(FALSE);
- str->Replace("\\&", "&");
- str->Replace("\\_", "_");
-}
+ // undo TeXFilter
+ static wxRegEx reNonSpecialSpecials("\\\\([#$%&_{}])"),
+ reAccents("\\\\verb|([~^])|");
-static void TeXFilter(wxString* str)
-{
- // FIXME may be done much more quickly
- str->Replace("&", "\\&");
- str->Replace("_", "\\_");
+ reNonSpecialSpecials.ReplaceAll(str, "\\1");
+ reAccents.ReplaceAll(str, "\\1");
}
static wxString GetAllComments(const spContext& ctx)
return s_timeBuffer;
}
+static const wxString GetVersionString()
+{
+ wxString version = "$Revision$";
+ wxRegEx("^\\$Revision$$").ReplaceFirst(&version, "\\1");
+ return version;
+}
+
/*
$Log$
+ Revision 1.22 2002/01/21 21:18:50 JS
+ Now adds 'include file' heading
+
+ Revision 1.21 2002/01/04 11:06:09 JS
+ Fixed missing membersections bug and also bug with functions not being written
+ in the right class
+
+ Revision 1.20 2002/01/03 14:23:33 JS
+ Added code to make it not duplicate membersections for overloaded functions
+
+ Revision 1.19 2002/01/03 13:34:12 JS
+ Added FlushAll to CloseClass, otherwise text was only flushed right at the end,
+ and appeared in one file.
+
+ Revision 1.18 2002/01/03 12:02:47 JS
+ Added main() and corrected VC++ project settings
+
+ Revision 1.17 2001/11/30 21:43:35 VZ
+ now the methods are sorted in the correct order in the generated docs
+
+ Revision 1.16 2001/11/28 19:27:33 VZ
+ HelpGen doesn't work in GUI mode
+
+ Revision 1.15 2001/11/22 21:59:58 GD
+ use "..." instead of <...> for wx headers
+
+ Revision 1.14 2001/07/19 13:51:29 VZ
+ fixes to version string
+
+ Revision 1.13 2001/07/19 13:44:57 VZ
+ 1. compilation fixes
+ 2. don't quote special characters inside verbatim environment
+
+ Revision 1.12 2000/10/09 13:53:33 juliansmart
+
+ Doc corrections; added HelpGen project files
+
+ Revision 1.11 2000/07/15 19:50:42 cvsuser
+ merged 2.2 branch
+
+ Revision 1.10.2.2 2000/03/27 15:33:10 VZ
+ don't trasnform output dir name to lower case
+
+ Revision 1.10 2000/03/11 10:05:23 VS
+ now compiles with wxBase
+
+ Revision 1.9 2000/01/16 13:25:21 VS
+ compilation fixes (gcc)
+
+ Revision 1.8 1999/09/13 14:29:39 JS
+
+ Made HelpGen into a wxWin app (still uses command-line args); moved includes
+ into src for simplicity; added VC++ 5 project file
+
+ 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: */