]> git.saurik.com Git - wxWidgets.git/blobdiff - utils/HelpGen/src/HelpGen.cpp
don't log mouse events by default
[wxWidgets.git] / utils / HelpGen / src / HelpGen.cpp
index b0cf803f22b51f3b99071f4b04ba7287a063434b..6828f792526ade66194ee14c6694dfe17c04d8d0 100644 (file)
@@ -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
    (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
 
    (iii) plans for version 3
     1. Merging with existing files
     #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>
 #endif // WX_PRECOMP
 
 #include <wx/file.h>
+#include <wx/regex.h>
 
 // C++ parsing classes
 #include "cjparser.h"
 
 // C++ parsing classes
 #include "cjparser.h"
 #include <stdio.h>
 #include <time.h>
 
 #include <stdio.h>
 #include <time.h>
 
+// argh, Windows defines this
+#ifdef GetCurrentTime
+#undef GetCurrentTime
+#endif
+
 // -----------------------------------------------------------------------------
 // global vars
 // -----------------------------------------------------------------------------
 
 // -----------------------------------------------------------------------------
 // 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
 
 // -----------------------------------------------------------------------------
 // private functions
@@ -91,12 +109,11 @@ static wxString GetAllComments(const spContext& ctx);
 
 // get the string with current time (returns pointer to static buffer)
 // timeFormat is used for the call of strftime(3)
 
 // 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);
 
 static const char *GetCurrentTime(const char *timeFormat);
 
+// get the string containing the program version
+static const wxString GetVersionString();
+
 // -----------------------------------------------------------------------------
 // private classes
 // -----------------------------------------------------------------------------
 // -----------------------------------------------------------------------------
 // private classes
 // -----------------------------------------------------------------------------
@@ -107,6 +124,14 @@ class wxTeXFile : public wxFile
 public:
     wxTeXFile() { }
 
 public:
     wxTeXFile() { }
 
+    // write a string to file verbatim (should only be used for the strings
+    // inside verbatim environment)
+    bool WriteVerbatim(const wxString& s)
+    {
+        return wxFile::Write(s);
+    }
+
+    // write a string quoting TeX specials in it
     bool WriteTeX(const wxString& s)
     {
         wxString t(s);
     bool WriteTeX(const wxString& s)
     {
         wxString t(s);
@@ -120,15 +145,70 @@ private:
     wxTeXFile& operator=(const wxTeXFile&);
 };
 
     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
 // 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 );
 
     virtual void VisitFile( spFile& fl );
     virtual void VisitClass( spClass& cl );
@@ -141,6 +221,9 @@ public:
 
     void EndVisit();
 
 
     void EndVisit();
 
+    // get our `ignore' object
+    IgnoreNamesHandler& GetIgnoreHandler() { return m_ignoreNames; }
+
     // shut up g++ warning (ain't it stupid?)
     virtual ~HelpGenVisitor() { }
 
     // shut up g++ warning (ain't it stupid?)
     virtual ~HelpGenVisitor() { }
 
@@ -160,7 +243,9 @@ protected:
     // terminate the function documentation if it was started
     void CloseFunction();
 
     // 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
     wxTeXFile m_file;           // file we're writing to now
 
     // state variables
@@ -171,13 +256,21 @@ protected:
          m_inFunction;      // we're parsing a function declaration
 
     // holders for "saved" documentation
          m_inFunction;      // we're parsing a function declaration
 
     // holders for "saved" documentation
-    wxString m_textStoredEnums,
-             m_textStoredTypedefs,
+    wxString m_textStoredTypedefs,
              m_textStoredFunctionComment;
 
              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;
 
     // 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&);
 private:
     HelpGenVisitor(const HelpGenVisitor&);
     HelpGenVisitor& operator=(const HelpGenVisitor&);
@@ -189,18 +282,18 @@ private:
 class DocManager
 {
 public:
 class DocManager
 {
 public:
-    DocManager() : m_ignore(CompareIgnoreListEntries) { }
+    DocManager(bool checkParamNames);
     ~DocManager();
 
     ~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;
 
     // 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
     // -----------------
 protected:
     // parsing TeX files
     // -----------------
@@ -242,40 +335,8 @@ protected:
 
     // functions and classes to ignore during diff
     // -------------------------------------------
 
     // 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)
     // -------------------------------------------------------------
 
     // information about all functions documented in the TeX file(s)
     // -------------------------------------------------------------
@@ -367,6 +428,13 @@ protected:
     // the class name appears in m_classes
     wxArrayString    m_classes;
     ArrayMethodInfos m_methods;
     // 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&);
 };
 
 // -----------------------------------------------------------------------------
 };
 
 // -----------------------------------------------------------------------------
@@ -380,16 +448,16 @@ protected:
 // this function never returns
 static void usage()
 {
 // 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 )
 #ifdef __WXMSW__
     if ( !basename )
-        basename = prog.BeforeLast('\\');
+        basename = prog.AfterLast('\\');
 #endif
     if ( !basename )
         basename = prog;
 
 #endif
     if ( !basename )
         basename = prog;
 
-    wxLogError(
+    wxLogMessage(
 "usage: %s [global options] <mode> [mode options] <files...>\n"
 "\n"
 "   where global options are:\n"
 "usage: %s [global options] <mode> [mode options] <files...>\n"
 "\n"
 "   where global options are:\n"
@@ -397,24 +465,26 @@ static void usage()
 "       -v          be verbose\n"
 "       -H          give this usage message\n"
 "       -V          print the version info\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"
 "\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"
 "       -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);
 }
 
 "\n", basename.c_str(), basename.c_str());
 
     exit(1);
 }
 
-int main(int argc, char **argv)
+int HelpGenApp::OnRun()
 {
     enum
     {
 {
     enum
     {
@@ -423,14 +493,15 @@ int main(int argc, char **argv)
         Mode_Diff
     } mode = Mode_None;
 
         Mode_Diff
     } mode = Mode_None;
 
-    g_argv = argv;
-
     if ( argc < 2 ) {
         usage();
     }
 
     wxArrayString filesH, filesTeX;
     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
 
     for ( int current = 1; current < argc ; current++ ) {
         // all options have one letter
@@ -450,22 +521,44 @@ int main(int argc, char **argv)
                     case 'H':
                         // help requested
                         usage();
                     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':
 
                     case 'i':
+                        current++;
+                        if ( current >= argc ) {
+                            wxLogError("-i option requires an argument.");
+
+                            break;
+                        }
+
+                        ignoreFile = argv[current];
+                        continue;
+
+                    case 'p':
                         if ( mode != Mode_Diff ) {
                         if ( mode != Mode_Diff ) {
-                            wxLogError("-i is only valid with diff.");
+                            wxLogError("-p is only valid with diff.");
 
                             break;
                         }
 
 
                             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;
                         }
 
 
                             break;
                         }
 
-                        ignoreFile = argv[current];
+                        overwrite = TRUE;
                         continue;
 
                     case 'o':
                         continue;
 
                     case 'o':
@@ -501,12 +594,16 @@ int main(int argc, char **argv)
                         continue;
 
                     default:
                         continue;
 
                     default:
+                        wxLogError("unknown option '%s'", argv[current]);
                         break;
                 }
             }
                         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
 
             // only get here after a break from switch or from else branch of if
-            wxLogError("unknown option '%s'", argv[current]);
 
             usage();
         }
 
             usage();
         }
@@ -517,7 +614,7 @@ int main(int argc, char **argv)
                 else if ( strcmp(argv[current], "dump") == 0 )
                     mode = Mode_Dump;
                 else {
                 else if ( strcmp(argv[current], "dump") == 0 )
                     mode = Mode_Dump;
                 else {
-                    wxLogError("unknown mode '%s'.");
+                    wxLogError("unknown mode '%s'.", argv[current]);
 
                     usage();
                 }
 
                     usage();
                 }
@@ -538,7 +635,10 @@ int main(int argc, char **argv)
 
     // create a parser object and a visitor derivation
     CJSourceParser parser;
 
     // 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
     spContext *ctxTop = NULL;
 
     // parse all header files
@@ -555,6 +655,11 @@ int main(int argc, char **argv)
             visitor.VisitAll(*ctxTop);
             visitor.EndVisit();
         }
             visitor.VisitAll(*ctxTop);
             visitor.EndVisit();
         }
+
+#ifdef __WXDEBUG__
+        if ( 0 && ctxTop )
+            ctxTop->Dump("");
+#endif // __WXDEBUG__
     }
 
     // parse all TeX files
     }
 
     // parse all TeX files
@@ -563,10 +668,10 @@ int main(int argc, char **argv)
             wxLogError("Can't complete diff.");
 
             // failure
             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++ ) {
 
         size_t nFiles = filesTeX.GetCount();
         for ( size_t n = 0; n < nFiles; n++ ) {
@@ -578,7 +683,7 @@ int main(int argc, char **argv)
         }
 
         if ( !!ignoreFile )
         }
 
         if ( !!ignoreFile )
-            docman.LoadIgnoreFile(ignoreFile);
+            docman.GetIgnoreHandler().AddNamesFromFile(ignoreFile);
 
         docman.DumpDifferences(ctxTop);
     }
 
         docman.DumpDifferences(ctxTop);
     }
@@ -590,6 +695,15 @@ int main(int argc, char **argv)
 // HelpGenVisitor implementation
 // -----------------------------------------------------------------------------
 
 // HelpGenVisitor implementation
 // -----------------------------------------------------------------------------
 
+HelpGenVisitor::HelpGenVisitor(const wxString& directoryOut,
+                               bool overwrite)
+              : m_directoryOut(directoryOut)
+{
+    m_overwrite = overwrite;
+
+    Reset();
+}
+
 void HelpGenVisitor::Reset()
 {
     m_inClass =
 void HelpGenVisitor::Reset()
 {
     m_inClass =
@@ -598,8 +712,10 @@ void HelpGenVisitor::Reset()
     m_inMethodSection = FALSE;
 
     m_textStoredTypedefs =
     m_inMethodSection = FALSE;
 
     m_textStoredTypedefs =
-    m_textStoredEnums =
     m_textStoredFunctionComment = "";
     m_textStoredFunctionComment = "";
+
+    m_storedEnums.Empty();
+    m_storedEnumsVerb.Empty();
     m_headers.Empty();
 }
 
     m_headers.Empty();
 }
 
@@ -611,8 +727,15 @@ void HelpGenVisitor::InsertTypedefDocs()
 
 void HelpGenVisitor::InsertEnumDocs()
 {
 
 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()
 }
 
 void HelpGenVisitor::InsertDataStructuresHeader()
@@ -620,7 +743,7 @@ void HelpGenVisitor::InsertDataStructuresHeader()
     if ( !m_inTypesSection ) {
         m_inTypesSection = TRUE;
 
     if ( !m_inTypesSection ) {
         m_inTypesSection = TRUE;
 
-        m_file.WriteTeX("\\wxheading{Data structures}\n\n");
+        m_file.Write("\\wxheading{Data structures}\n\n");
     }
 }
 
     }
 }
 
@@ -629,7 +752,7 @@ void HelpGenVisitor::InsertMethodsHeader()
     if ( !m_inMethodSection ) {
         m_inMethodSection = TRUE;
 
     if ( !m_inMethodSection ) {
         m_inMethodSection = TRUE;
 
-        m_file.WriteTeX( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
+        m_file.Write( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
     }
 }
 
     }
 }
 
@@ -645,11 +768,10 @@ void HelpGenVisitor::CloseFunction()
         }
 
         totalText << "}\n\n";
         }
 
         totalText << "}\n\n";
+        m_file.Write(totalText);
 
         if ( !m_textStoredFunctionComment.IsEmpty() )
 
         if ( !m_textStoredFunctionComment.IsEmpty() )
-            totalText << m_textStoredFunctionComment << '\n';
-
-        m_file.WriteTeX(totalText);
+            m_file.WriteTeX(m_textStoredFunctionComment + '\n');
     }
 }
 
     }
 }
 
@@ -657,23 +779,34 @@ void HelpGenVisitor::EndVisit()
 {
     CloseFunction();
 
 {
     CloseFunction();
 
+    m_fileHeader.Empty();
+
     wxLogVerbose("%s: finished generating for the current file.",
                  GetCurrentTime("%H:%M:%S"));
 }
 
 void HelpGenVisitor::VisitFile( spFile& file )
 {
     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'...",
     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 )
 {
 }
 
 void HelpGenVisitor::VisitClass( spClass& cl )
 {
+    m_inClass = FALSE; // will be left FALSE on error
+
     wxString name = cl.GetName();
 
     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
     // 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;
     }
     if ( name(0, 2) == "wx" ) {
         filename << name.c_str() + 2;
     }
@@ -683,13 +816,12 @@ void HelpGenVisitor::VisitClass( spClass& cl )
 
     filename.MakeLower();
     filename += ".tex";
 
     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());
 
                    filename.c_str());
 
-        m_inClass = FALSE;
-
         return;
     }
 
         return;
     }
 
@@ -707,25 +839,26 @@ void HelpGenVisitor::VisitClass( spClass& cl )
     wxLogInfo("Created new file '%s' for class '%s'.",
               filename.c_str(), name.c_str());
 
     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.Write(header);
+
     // the entire text we're writing to file
     wxString totalText;
 
     // 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() ) {
     // if the header includes other headers they must be related to it... try to
     // automatically generate the "See also" clause
     if ( !m_headers.IsEmpty() ) {
@@ -847,25 +980,25 @@ void HelpGenVisitor::VisitEnumeration( spEnumeration& en )
     }
 
     // simply copy the enum text in the docs
     }
 
     // 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 ) {
 
     // 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();
 
     }
     else {
         // write the header for this section if not done yet
         InsertDataStructuresHeader();
 
-        enumeration << '\n';
         m_file.WriteTeX(enumeration);
         m_file.WriteTeX(enumeration);
+        m_file.WriteVerbatim(enumerationVerb);
+        m_file.Write('\n');
     }
 }
 
     }
 }
 
@@ -931,8 +1064,14 @@ void HelpGenVisitor::VisitOperation( spOperation& op )
 {
     CloseFunction();
 
 {
     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;
         wxLogWarning("skipped global function '%s'.", op.GetName().c_str());
 
         return;
@@ -943,6 +1082,15 @@ void HelpGenVisitor::VisitOperation( spOperation& op )
         return;
     }
 
         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
     InsertMethodsHeader();
 
     // save state info
@@ -953,13 +1101,11 @@ void HelpGenVisitor::VisitOperation( spOperation& op )
 
     // start function documentation
     wxString totalText;
 
     // 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;
 
     // 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;
     }
 
         funcname = dtor;
     }
 
@@ -967,12 +1113,12 @@ void HelpGenVisitor::VisitOperation( spOperation& op )
                      "\\membersection{%s::%s}\\label{%s}\n"
                      "\n"
                      "\\%sfunc{%s%s}{%s}{",
                      "\\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(),
                      MakeLabel(classname, funcname).c_str(),
                      op.mIsConstant ? "const" : "",
                      op.mIsVirtual ? "virtual " : "",
                      op.mRetType.c_str(),
-                     funcname);
+                     funcname.c_str());
 
     m_file.WriteTeX(totalText);
 }
 
     m_file.WriteTeX(totalText);
 }
@@ -1005,6 +1151,11 @@ void HelpGenVisitor::VisitParameter( spParameter& param )
 // DocManager
 // ---------------------------------------------------------------------------
 
 // DocManager
 // ---------------------------------------------------------------------------
 
+DocManager::DocManager(bool checkParamNames)
+{
+    m_checkParamNames = checkParamNames;
+}
+
 size_t DocManager::TryMatch(const char *str, const char *match)
 {
     size_t lenMatch = 0;
 size_t DocManager::TryMatch(const char *str, const char *match)
 {
     size_t lenMatch = 0;
@@ -1280,7 +1431,7 @@ bool DocManager::ParseTeXFile(const wxString& filename)
         lenMatch = TryMatch(current, "void");
         if ( !lenMatch ) {
             lenMatch = TryMatch(current, "param");
         lenMatch = TryMatch(current, "void");
         if ( !lenMatch ) {
             lenMatch = TryMatch(current, "param");
-            while ( lenMatch ) {
+            while ( lenMatch && (current - buf < len) ) {
                 current += lenMatch;
 
                 // now come {paramtype}{paramname}
                 current += lenMatch;
 
                 // now come {paramtype}{paramname}
@@ -1423,7 +1574,7 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const
         const wxString& nameClass = ctxClass->mName;
         int index = m_classes.Index(nameClass);
         if ( index == wxNOT_FOUND ) {
         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.",
                 foundDiff = TRUE;
 
                 wxLogError("Class '%s' is not documented at all.",
@@ -1466,7 +1617,7 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const
             }
 
             if ( aMethodsWithSameName.IsEmpty() && ctxMethod->IsPublic() ) {
             }
 
             if ( aMethodsWithSameName.IsEmpty() && ctxMethod->IsPublic() ) {
-                if ( !IgnoreMethod(nameClass, nameMethod) ) {
+                if ( !m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) {
                     foundDiff = TRUE;
 
                     wxLogError("'%s::%s' is not documented.",
                     foundDiff = TRUE;
 
                     wxLogError("'%s::%s' is not documented.",
@@ -1481,7 +1632,7 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const
                 index = (size_t)aMethodsWithSameName[0u];
                 methodExists[index] = TRUE;
 
                 index = (size_t)aMethodsWithSameName[0u];
                 methodExists[index] = TRUE;
 
-                if ( IgnoreMethod(nameClass, nameMethod) )
+                if ( m_ignoreNames.IgnoreMethod(nameClass, nameMethod) )
                     continue;
 
                 if ( !ctxMethod->IsPublic() ) {
                     continue;
 
                 if ( !ctxMethod->IsPublic() ) {
@@ -1533,7 +1684,8 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const
 
                         spParameter *ctxParam = (spParameter *)ctx;
                         const ParamInfo& param = method.GetParam(nParam);
 
                         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 "
                             foundDiff = TRUE;
 
                             wxLogError("Parameter #%d of '%s::%s' should be "
@@ -1575,9 +1727,9 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const
                 }
             }
             else {
                 }
             }
             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 ) {
                     continue;
 
                 if ( aOverloadedMethods.Index(nameMethod) == wxNOT_FOUND ) {
@@ -1602,7 +1754,7 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const
         for ( nMethod = 0; nMethod < countMethods; nMethod++ ) {
             if ( !methodExists[nMethod] ) {
                 const wxString& nameMethod = methods[nMethod]->GetName();
         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.",
                     foundDiff = TRUE;
 
                     wxLogError("'%s::%s' is documented but doesn't exist.",
@@ -1633,11 +1785,14 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const
 DocManager::~DocManager()
 {
     WX_CLEAR_ARRAY(m_methods);
 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);
 {
     // first compare the classes
     int rc = first->m_classname.Cmp(second->m_classname);
@@ -1647,7 +1802,7 @@ int DocManager::CompareIgnoreListEntries(IgnoreListEntry *first,
     return rc;
 }
 
     return rc;
 }
 
-bool DocManager::LoadIgnoreFile(const wxString& filename)
+bool IgnoreNamesHandler::AddNamesFromFile(const wxString& filename)
 {
     wxFile file(filename, wxFile::read);
     if ( !file.IsOpened() )
 {
     wxFile file(filename, wxFile::read);
     if ( !file.IsOpened() )
@@ -1749,21 +1904,33 @@ static wxString MakeHelpref(const char *argument)
     return helpref;
 }
 
     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);
 
 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)
 }
 
 static wxString GetAllComments(const spContext& ctx)
@@ -1801,13 +1968,89 @@ static const char *GetCurrentTime(const char *timeFormat)
     return s_timeBuffer;
 }
 
     return s_timeBuffer;
 }
 
+static const wxString GetVersionString()
+{
+    wxString version = "$Revision$";
+    wxRegEx("^\\$Revision$$").ReplaceFirst(&version, "\\1");
+    return version;
+}
+
 /*
    $Log$
 /*
    $Log$
+   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.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: */
 */
 
 /* vi: set tw=80 et ts=4 sw=4: */