// 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/regex.h>
- #include <wx/dynarray.h>
- #include <wx/wx.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"
#undef GetCurrentTime
#endif
-// ----------------------------------------------------------------------------
-// constants
-// ----------------------------------------------------------------------------
-
-#define VERSION_STRING "$Revision$"
-
// -----------------------------------------------------------------------------
// global vars
// -----------------------------------------------------------------------------
virtual int OnRun();
};
-IMPLEMENT_APP(HelpGenApp);
+// IMPLEMENT_APP(HelpGenApp);
// -----------------------------------------------------------------------------
// private functions
// timeFormat is used for the call of strftime(3)
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:
// 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
// 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?
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,
DocManager& operator=(const DocManager&);
};
-// -----------------------------------------------------------------------------
-// private functions
-// -----------------------------------------------------------------------------
-
// =============================================================================
// implementation
// =============================================================================
// version requested
wxLogMessage("HelpGen version %s\n"
"(c) 1999-2001 Vadim Zeitlin\n",
- VERSION_STRING);
+ GetVersionString().c_str());
return 0;
case 'i':
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
// -----------------------------------------------------------------------------
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();
if ( !m_inTypesSection ) {
m_inTypesSection = TRUE;
- m_file.Write("\\wxheading{Data structures}\n\n");
+ m_file.WriteVerbatim("\\wxheading{Data structures}\n\n");
}
}
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"));
}
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();
"\n"
"\n"
"\\section{\\class{%s}}\\label{%s}\n\n",
- VERSION_STRING,
+ 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);
+ m_file.WriteVerbatim(header);
// the entire text we're writing to file
wxString totalText;
}
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 )
m_file.WriteTeX(enumeration);
m_file.WriteVerbatim(enumerationVerb);
- m_file.Write('\n');
+ m_file.WriteVerbatim('\n');
}
}
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;
}
InsertMethodsHeader();
// save state info
- m_inFunction =
+ m_funcName = funcname;
m_isFirstParam = TRUE;
m_textStoredFunctionComment = GetAllComments(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 << '}';
}
// ---------------------------------------------------------------------------
}
}
- 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 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