]> git.saurik.com Git - wxWidgets.git/blobdiff - utils/HelpGen/src/HelpGen.cpp
cleaning up the mess created by the FloodFill patch
[wxWidgets.git] / utils / HelpGen / src / HelpGen.cpp
index 9fed79e63bfa667e9203a383e1268f9877ec6805..4bf5e4418fa397e70e0efe831609e7754b5803e7 100644 (file)
 // 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"
@@ -60,6 +64,7 @@
 
 #include "wx/file.h"
 #include "wx/regex.h"
+#include "wx/hash.h"
 
 // C++ parsing classes
 #include "cjparser.h"
@@ -88,7 +93,7 @@ public:
     virtual int OnRun();
 };
 
-IMPLEMENT_APP(HelpGenApp);
+// IMPLEMENT_APP(HelpGenApp);
 
 // -----------------------------------------------------------------------------
 // private functions
@@ -118,7 +123,70 @@ 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:
@@ -126,23 +194,42 @@ public:
 
     // write a string to file verbatim (should only be used for the strings
     // inside verbatim environment)
-    bool WriteVerbatim(const wxString& s)
+    void WriteVerbatim(const wxString& s)
     {
-        return wxFile::Write(s);
+        m_text += s;
     }
 
     // write a string quoting TeX specials in it
-    bool WriteTeX(const wxString& s)
+    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
@@ -243,6 +330,10 @@ protected:
     // terminate the function documentation if it was started
     void CloseFunction();
 
+    // 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?
@@ -252,8 +343,18 @@ protected:
     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_textStoredTypedefs,
@@ -437,10 +538,6 @@ private:
     DocManager& operator=(const DocManager&);
 };
 
-// -----------------------------------------------------------------------------
-// private functions
-// -----------------------------------------------------------------------------
-
 // =============================================================================
 // implementation
 // =============================================================================
@@ -691,6 +788,21 @@ int HelpGenApp::OnRun()
     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
 // -----------------------------------------------------------------------------
@@ -707,13 +819,17 @@ HelpGenVisitor::HelpGenVisitor(const wxString& directoryOut,
 void HelpGenVisitor::Reset()
 {
     m_inClass =
-    m_inFunction =
     m_inTypesSection =
     m_inMethodSection = FALSE;
 
+    m_classname =
+    m_funcName =
+    m_textFunc =
     m_textStoredTypedefs =
     m_textStoredFunctionComment = "";
 
+    m_arrayFuncDocs.Empty();
+
     m_storedEnums.Empty();
     m_storedEnumsVerb.Empty();
     m_headers.Empty();
@@ -743,7 +859,7 @@ void HelpGenVisitor::InsertDataStructuresHeader()
     if ( !m_inTypesSection ) {
         m_inTypesSection = TRUE;
 
-        m_file.Write("\\wxheading{Data structures}\n\n");
+        m_file.WriteVerbatim("\\wxheading{Data structures}\n\n");
     }
 }
 
@@ -752,35 +868,96 @@ void HelpGenVisitor::InsertMethodsHeader()
     if ( !m_inMethodSection ) {
         m_inMethodSection = TRUE;
 
-        m_file.Write( "\\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_file.Write(totalText);
+        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);
+            }
+
+            m_arrayFuncDocs.Empty();
+        }
 
-        if ( !m_textStoredFunctionComment.IsEmpty() )
-            m_file.WriteTeX(m_textStoredFunctionComment + '\n');
+        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"));
 }
@@ -794,7 +971,13 @@ void HelpGenVisitor::VisitFile( spFile& file )
 
 void HelpGenVisitor::VisitClass( spClass& cl )
 {
-    m_inClass = FALSE; // will be left FALSE on error
+    CloseClass();
+
+       if (m_file.IsOpened())
+       {
+               m_file.Flush();
+               m_file.Close();
+       }
 
     wxString name = cl.GetName();
 
@@ -854,7 +1037,7 @@ void HelpGenVisitor::VisitClass( spClass& cl )
                   name.c_str(),
                   wxString(name).MakeLower().c_str());
 
-    m_file.Write(header);
+    m_file.WriteVerbatim(header);
 
     // the entire text we're writing to file
     wxString totalText;
@@ -957,6 +1140,12 @@ void HelpGenVisitor::VisitClass( spClass& cl )
     }
     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);
 
@@ -964,6 +1153,8 @@ void HelpGenVisitor::VisitClass( spClass& cl )
     InsertDataStructuresHeader();
     InsertTypedefDocs();
     InsertEnumDocs();
+
+       //m_file.Flush();
 }
 
 void HelpGenVisitor::VisitEnumeration( spEnumeration& en )
@@ -998,7 +1189,7 @@ void HelpGenVisitor::VisitEnumeration( spEnumeration& en )
 
         m_file.WriteTeX(enumeration);
         m_file.WriteVerbatim(enumerationVerb);
-        m_file.Write('\n');
+        m_file.WriteVerbatim('\n');
     }
 }
 
@@ -1082,11 +1273,12 @@ void HelpGenVisitor::VisitOperation( spOperation& op )
         return;
     }
 
-    wxString funcname = op.GetName(),
-             classname = op.GetClass().GetName();
-    if ( m_ignoreNames.IgnoreMethod(classname, funcname) ) {
+    m_classname = op.GetClass().GetName();
+    wxString funcname = op.GetName();
+
+    if ( m_ignoreNames.IgnoreMethod(m_classname, funcname) ) {
         wxLogVerbose("Skipping ignored '%s::%s'.",
-                     classname.c_str(), funcname.c_str());
+                     m_classname.c_str(), funcname.c_str());
 
         return;
     }
@@ -1094,7 +1286,7 @@ void HelpGenVisitor::VisitOperation( spOperation& op )
     InsertMethodsHeader();
 
     // save state info
-    m_inFunction =
+    m_funcName = funcname;
     m_isFirstParam = TRUE;
 
     m_textStoredFunctionComment = GetAllComments(op);
@@ -1104,47 +1296,45 @@ void HelpGenVisitor::VisitOperation( spOperation& op )
 
     // check for the special case of dtor
     wxString dtor;
-    if ( (funcname[0] == '~') && (classname == funcname.c_str() + 1) ) {
-        dtor.Printf("\\destruct{%s}", classname.c_str());
+    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.c_str(), funcname.c_str(),
-                     MakeLabel(classname, funcname).c_str(),
-                     op.mIsConstant ? "const" : "",
-                     op.mIsVirtual ? "virtual " : "",
-                     op.mRetType.c_str(),
-                     funcname.c_str());
-
-    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 << '}';
 }
 
 // ---------------------------------------------------------------------------
@@ -1888,8 +2078,44 @@ static wxString MakeLabel(const char *classname, const char *funcname)
         }
     }
 
-    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();
 
@@ -1977,6 +2203,29 @@ static const wxString GetVersionString()
 
 /*
    $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