X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5f7cf62fbf9e25146b796e3e6476e6693c2d2e02..6ce8b8484654b5ab073951373c93d9bdd8221881:/utils/HelpGen/src/HelpGen.cpp diff --git a/utils/HelpGen/src/HelpGen.cpp b/utils/HelpGen/src/HelpGen.cpp index b0cf803f22..47b9ae8726 100644 --- a/utils/HelpGen/src/HelpGen.cpp +++ b/utils/HelpGen/src/HelpGen.cpp @@ -6,7 +6,7 @@ // Created: 06/01/99 // RCS-ID: $Id$ // Copyright: (c) 1999 VZ -// Licence: GPL +// Licence: wxWindows Licence ///////////////////////////////////////////////////////////////////////////// /* @@ -33,6 +33,7 @@ (ii) plans for version 2 1. Use wxTextFile for direct file access to avoid one scan method problems 2. Use command line parser class for the options + 3. support for overloaded functions in diff mode (search for OVER) (iii) plans for version 3 1. Merging with existing files @@ -47,16 +48,27 @@ // headers // ----------------------------------------------------------------------------- -// wxWindows +// wxWidgets #include "wx/wxprec.h" +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_UNICODE + #error "HelpGen doesn't build in Unicode mode" +#endif + #ifndef WX_PRECOMP - #include - #include - #include + #include "wx/string.h" + #include "wx/log.h" + #include "wx/dynarray.h" + #include "wx/app.h" #endif // WX_PRECOMP -#include +#include "wx/file.h" +#include "wx/regex.h" +#include "wx/hash.h" // C++ parsing classes #include "cjparser.h" @@ -65,22 +77,15 @@ #include #include -// ----------------------------------------------------------------------------- -// global vars -// ----------------------------------------------------------------------------- - -// just a copy of argv -static char **g_argv = NULL; - // ----------------------------------------------------------------------------- // private functions // ----------------------------------------------------------------------------- // return the label for the given function name (i.e. argument of \label) -static wxString MakeLabel(const char *classname, const char *funcname = NULL); +static wxString MakeLabel(const wxChar *classname, const wxChar *funcname = NULL); // return the whole \helpref{arg}{arg_label} string -static wxString MakeHelpref(const char *argument); +static wxString MakeHelpref(const wxChar *argument); // [un]quote special TeX characters (in place) static void TeXFilter(wxString* str); @@ -91,33 +96,182 @@ 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) -#ifdef GetCurrentTime -#undef GetCurrentTime -#endif +static const char *GetCurrentTimeFormatted(const char *timeFormat); -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(_T("~")) + 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 wxStrcmp((*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(_T("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, wxEmptyString); + + 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 +public: // FIXME: macro requires it + WX_DEFINE_SORTED_ARRAY(IgnoreListEntry *, ArrayNamesToIgnore); + +protected: + ArrayNamesToIgnore m_ignore; + +private: + IgnoreNamesHandler(const IgnoreNamesHandler&); + IgnoreNamesHandler& operator=(const IgnoreNamesHandler&); }; // visitor implementation which writes all collected data to a .tex file @@ -125,10 +279,7 @@ class HelpGenVisitor : public spVisitor { public: // ctor - HelpGenVisitor(const wxString& directoryOut) : m_directoryOut(directoryOut) - { - Reset(); - } + HelpGenVisitor(const wxString& directoryOut, bool overwrite); virtual void VisitFile( spFile& fl ); virtual void VisitClass( spClass& cl ); @@ -141,6 +292,9 @@ public: void EndVisit(); + // get our `ignore' object + IgnoreNamesHandler& GetIgnoreHandler() { return m_ignoreNames; } + // shut up g++ warning (ain't it stupid?) virtual ~HelpGenVisitor() { } @@ -160,24 +314,48 @@ protected: // 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 + 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&); @@ -189,25 +367,25 @@ private: class DocManager { public: - DocManager() : m_ignore(CompareIgnoreListEntries) { } + DocManager(bool checkParamNames); ~DocManager(); - // load file with class names and function names to ignore during diff - bool LoadIgnoreFile(const wxString& filename); - - // returns FALSE on failure + // returns false on failure bool ParseTeXFile(const wxString& filename); - // returns FALSE if there were any differences + // 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 // ----------------- // returns the length of 'match' if the string 'str' starts with it or 0 // otherwise - static size_t TryMatch(const char *str, const char *match); + static size_t TryMatch(const wxChar *str, const wxChar *match); // skip spaces: returns pointer to first non space character (also // updates the value of m_line) @@ -222,12 +400,12 @@ protected: } // skips characters until the next 'c' in '*pp' unless it ends before in - // which case FALSE is returned and pp points to '\0', otherwise TRUE is + // which case false is returned and pp points to '\0', otherwise true is // returned and pp points to 'c' bool SkipUntil(const char **pp, char c); // the same as SkipUntil() but only spaces are skipped: on first non space - // character different from 'c' the function stops and returns FALSE + // character different from 'c' the function stops and returns false bool SkipSpaceUntil(const char **pp, char c); // extract the string between {} and modify '*pp' to point at the @@ -242,44 +420,14 @@ protected: // functions and classes to ignore during diff // ------------------------------------------- - struct IgnoreListEntry - { - IgnoreListEntry(const wxString& classname, - const wxString& funcname) - : m_classname(classname), m_funcname(funcname) - { - } - - wxString m_classname; - wxString m_funcname; // if empty, ignore class entirely - }; - static int CompareIgnoreListEntries(IgnoreListEntry *first, - IgnoreListEntry *second); - - // for efficiency, let's sort it - WX_DEFINE_SORTED_ARRAY(IgnoreListEntry *, ArrayNamesToIgnore); - - ArrayNamesToIgnore m_ignore; - - // return TRUE if we ignore this function - bool IgnoreMethod(const wxString& classname, - const wxString& funcname) const - { - IgnoreListEntry ignore(classname, funcname); - - return m_ignore.Index(&ignore) != wxNOT_FOUND; - } - - // return TRUE if we ignore this class entirely - bool IgnoreClass(const wxString& classname) const - { - return IgnoreMethod(classname, ""); - } + IgnoreNamesHandler m_ignoreNames; // information about all functions documented in the TeX file(s) // ------------------------------------------------------------- +public: // Note: Sun C++ 5.5 requires TypeInfo and ParamInfo to be public + // info about a type: for now stored as text string, but must be parsed // further later (to know that "char *" == "char []" - TODO) class TypeInfo @@ -296,6 +444,8 @@ protected: wxString m_type; }; + friend class ParamInfo; // for access to TypeInfo + // info abotu a function parameter class ParamInfo { @@ -317,7 +467,8 @@ protected: wxString m_value; // default value }; - WX_DEFINE_ARRAY(ParamInfo *, ArrayParamInfo); +public: // FIXME: macro requires it + WX_DEFINE_ARRAY_PTR(ParamInfo *, ArrayParamInfo); // info about a function struct MethodInfo @@ -359,37 +510,43 @@ protected: ArrayParamInfo m_params; }; - WX_DEFINE_ARRAY(MethodInfo *, ArrayMethodInfo); - WX_DEFINE_ARRAY(ArrayMethodInfo *, ArrayMethodInfos); + WX_DEFINE_ARRAY_PTR(MethodInfo *, ArrayMethodInfo); + WX_DEFINE_ARRAY_PTR(ArrayMethodInfo *, ArrayMethodInfos); +private: // first array contains the names of all classes we found, the second has a // pointer to the array of methods of the given class at the same index as // 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 // ============================================================================= +static char **g_argv = NULL; + // this function never returns static void usage() { wxString prog = g_argv[0]; - wxString basename = prog.BeforeLast('/'); + 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 options] \n" "\n" " where global options are:\n" @@ -397,18 +554,20 @@ static void usage() " -v be verbose\n" " -H give this usage message\n" " -V print the version info\n" +" -i file file with classes/function to ignore\n" "\n" " where mode is one of: dump, diff\n" "\n" " dump means generate .tex files for TeX2RTF converter from specified\n" " headers files, mode options are:\n" +" -f overwrite existing files\n" " -o outdir directory for generated files\n" "\n" " diff means compare the set of methods documented .tex file with the\n" " methods declared in the header:\n" " %s diff .\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); @@ -416,6 +575,16 @@ static void usage() int main(int argc, char **argv) { + g_argv = argv; + + wxInitializer initializer; + if ( !initializer ) + { + fprintf(stderr, "Failed to initialize the wxWidgets library, aborting."); + + return -1; + } + enum { Mode_None, @@ -423,14 +592,15 @@ int main(int argc, char **argv) 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 @@ -444,28 +614,50 @@ int main(int argc, char **argv) case 'q': // be quiet - wxLog::GetActiveTarget()->SetVerbose(FALSE); + wxLog::GetActiveTarget()->SetVerbose(false); continue; 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': @@ -483,7 +675,7 @@ int main(int argc, char **argv) } directoryOut = argv[current]; - if ( !!directoryOut ) { + if ( !directoryOut.empty() ) { // terminate with a '/' if it doesn't have it switch ( directoryOut.Last() ) { case '/': @@ -501,12 +693,16 @@ int main(int argc, char **argv) continue; default: + wxLogError("unknown option '%s'", argv[current]); break; } } + else { + wxLogError("only one letter options are allowed, not '%s'.", + argv[current]); + } // only get here after a break from switch or from else branch of if - wxLogError("unknown option '%s'", argv[current]); usage(); } @@ -517,7 +713,7 @@ int main(int argc, char **argv) else if ( strcmp(argv[current], "dump") == 0 ) mode = Mode_Dump; else { - wxLogError("unknown mode '%s'."); + wxLogError("unknown mode '%s'.", argv[current]); usage(); } @@ -538,7 +734,10 @@ int main(int argc, char **argv) // create a parser object and a visitor derivation CJSourceParser parser; - HelpGenVisitor visitor(directoryOut); + HelpGenVisitor visitor(directoryOut, overwrite); + if ( !ignoreFile.empty() && mode == Mode_Dump ) + visitor.GetIgnoreHandler().AddNamesFromFile(ignoreFile); + spContext *ctxTop = NULL; // parse all header files @@ -551,10 +750,15 @@ int main(int argc, char **argv) header.c_str()); } else if ( mode == Mode_Dump ) { - ((spFile *)ctxTop)->mFileName = header; + ((spFile *)ctxTop)->m_FileName = header; visitor.VisitAll(*ctxTop); visitor.EndVisit(); } + +#ifdef __WXDEBUG__ + if ( 0 && ctxTop ) + ctxTop->Dump(wxEmptyString); +#endif // __WXDEBUG__ } // parse all TeX files @@ -563,10 +767,10 @@ int main(int argc, char **argv) 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++ ) { @@ -577,8 +781,8 @@ int main(int argc, char **argv) } } - if ( !!ignoreFile ) - docman.LoadIgnoreFile(ignoreFile); + if ( !ignoreFile.empty() ) + docman.GetIgnoreHandler().AddNamesFromFile(ignoreFile); docman.DumpDifferences(ctxTop); } @@ -590,16 +794,31 @@ int main(int argc, char **argv) // HelpGenVisitor implementation // ----------------------------------------------------------------------------- +HelpGenVisitor::HelpGenVisitor(const wxString& directoryOut, + bool overwrite) + : m_directoryOut(directoryOut) +{ + m_overwrite = overwrite; + + Reset(); +} + void HelpGenVisitor::Reset() { m_inClass = - m_inFunction = m_inTypesSection = - m_inMethodSection = FALSE; + m_inMethodSection = false; + m_classname = + m_funcName = + m_textFunc = m_textStoredTypedefs = - m_textStoredEnums = - m_textStoredFunctionComment = ""; + m_textStoredFunctionComment = wxEmptyString; + + m_arrayFuncDocs.Empty(); + + m_storedEnums.Empty(); + m_storedEnumsVerb.Empty(); m_headers.Empty(); } @@ -611,69 +830,155 @@ void HelpGenVisitor::InsertTypedefDocs() 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_inTypesSection = true; - m_file.WriteTeX("\\wxheading{Data structures}\n\n"); + m_file.WriteVerbatim("\\wxheading{Data structures}\n\n"); } } void HelpGenVisitor::InsertMethodsHeader() { if ( !m_inMethodSection ) { - m_inMethodSection = TRUE; + 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"; } - totalText << "}\n\n"; + m_textFunc << "}\n\n"; - if ( !m_textStoredFunctionComment.IsEmpty() ) - totalText << m_textStoredFunctionComment << '\n'; + if ( !m_textStoredFunctionComment.empty() ) { + m_textFunc << m_textStoredFunctionComment << '\n'; + } + + m_arrayFuncDocs.Add(new FunctionDocEntry(m_funcName, m_textFunc)); - m_file.WriteTeX(totalText); + 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(_T("\\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.c_str(), & membersections); + } + } + + for ( n = 0; n < count; n++ ) { + m_file.WriteTeX(m_arrayFuncDocs[n].text); + } + + m_arrayFuncDocs.Empty(); + } + + 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")); + GetCurrentTimeFormatted("%H:%M:%S")); } void HelpGenVisitor::VisitFile( spFile& file ) { + m_fileHeader = file.m_FileName; wxLogVerbose("%s: started generating docs for classes from file '%s'...", - GetCurrentTime("%H:%M:%S"), file.mFileName.c_str()); + GetCurrentTimeFormatted("%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; } @@ -683,13 +988,12 @@ void HelpGenVisitor::VisitClass( spClass& cl ) 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; } @@ -702,34 +1006,35 @@ void HelpGenVisitor::VisitClass( spClass& cl ) } m_inMethodSection = - m_inTypesSection = FALSE; + m_inTypesSection = false; 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(), + GetCurrentTimeFormatted("%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() ) { - // correspondence between wxWindows headers and class names + // correspondence between wxWidgets headers and class names static const char *headers[] = { "object", "defs", @@ -800,12 +1105,12 @@ void HelpGenVisitor::VisitClass( spClass& cl ) // derived from section wxString derived = "\\wxheading{Derived from}\n\n"; - const StrListT& baseClasses = cl.mSuperClassNames; + const StrListT& baseClasses = cl.m_SuperClassNames; if ( baseClasses.size() == 0 ) { derived << "No base class"; } else { - bool first = TRUE; + bool first = true; for ( StrListT::const_iterator i = baseClasses.begin(); i != baseClasses.end(); i++ ) { @@ -814,7 +1119,7 @@ void HelpGenVisitor::VisitClass( spClass& cl ) derived << "\\\\\n"; } else { - first = FALSE; + first = false; } wxString baseclass = *i; @@ -824,6 +1129,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); @@ -831,6 +1142,8 @@ void HelpGenVisitor::VisitClass( spClass& cl ) InsertDataStructuresHeader(); InsertTypedefDocs(); InsertEnumDocs(); + + //m_file.Flush(); } void HelpGenVisitor::VisitEnumeration( spEnumeration& en ) @@ -847,25 +1160,25 @@ 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 << _T("\\begin{verbatim}\n") + << en.m_EnumContent + << _T("\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'); } } @@ -881,14 +1194,14 @@ void HelpGenVisitor::VisitTypeDef( spTypeDef& td ) } wxString typedefdoc; - typedefdoc << "{\\small \\begin{verbatim}\n" - << "typedef " << td.mOriginalType << ' ' << td.GetName() - << "\n\\end{verbatim}}\n" + typedefdoc << _T("{\\small \\begin{verbatim}\n") + << _T("typedef ") << td.m_OriginalType << _T(' ') << td.GetName() + << _T("\n\\end{verbatim}}\n") << GetAllComments(td); // remember for later use if we're not inside a class yet if ( !m_inClass ) { - if ( !m_textStoredTypedefs.IsEmpty() ) { + if ( !m_textStoredTypedefs.empty() ) { m_textStoredTypedefs << '\n'; } @@ -931,8 +1244,14 @@ void HelpGenVisitor::VisitOperation( spOperation& op ) { CloseFunction(); - if ( !m_inClass || !op.IsInClass() ) { - // FIXME that's a bug too + if ( !m_inClass ) { + // we don't generate docs right now - either we ignore this class + // entirely or we couldn't open the file + return; + } + + if ( !op.IsInClass() ) { + // TODO document global functions wxLogWarning("skipped global function '%s'.", op.GetName().c_str()); return; @@ -943,68 +1262,85 @@ void HelpGenVisitor::VisitOperation( spOperation& op ) 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_isFirstParam = TRUE; + 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[0u] == '~') && (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 constStr; + if(op.mIsConstant) constStr = _T("const"); + + wxString virtualStr; + if(op.mIsVirtual) virtualStr = _T("virtual "); + + wxString func; + func.Printf(_T("\n") + _T("\\%sfunc{%s%s}{%s}{"), + constStr.c_str(), + virtualStr.c_str(), + op.m_RetType.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; + m_isFirstParam = false; } else { - totalText << ", "; + m_textFunc << ", "; } - totalText << "\\param{" << param.mType << " }{" << param.GetName(); - wxString defvalue = param.mInitVal; - if ( !defvalue.IsEmpty() ) { - totalText << " = " << defvalue; + m_textFunc << "\\param{" << param.m_Type << " }{" << param.GetName(); + wxString defvalue = param.m_InitVal; + if ( !defvalue.empty() ) { + 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; @@ -1060,7 +1396,7 @@ wxString DocManager::ExtractStringBetweenBraces(const char **pp) if ( !SkipSpaceUntil(pp, '{') ) { wxLogWarning("file %s(%d): '{' expected after '\\param'", - m_filename.c_str(), m_line); + m_filename.c_str(), (int)m_line); } else { @@ -1068,7 +1404,7 @@ wxString DocManager::ExtractStringBetweenBraces(const char **pp) if ( !SkipUntil(pp, '}') ) { wxLogWarning("file %s(%d): '}' expected after '\\param'", - m_filename.c_str(), m_line); + m_filename.c_str(), (int)m_line); } else { result = wxString(startParam, (*pp)++ - startParam); @@ -1084,11 +1420,11 @@ bool DocManager::ParseTeXFile(const wxString& filename) wxFile file(m_filename, wxFile::read); if ( !file.IsOpened() ) - return FALSE; + return false; off_t len = file.Length(); if ( len == wxInvalidOffset ) - return FALSE; + return false; char *buf = new char[len + 1]; buf[len] = '\0'; @@ -1096,18 +1432,18 @@ bool DocManager::ParseTeXFile(const wxString& filename) if ( file.Read(buf, len) == wxInvalidOffset ) { delete [] buf; - return FALSE; + return false; } // reinit everything m_line = 1; wxLogVerbose("%s: starting to parse doc file '%s'.", - GetCurrentTime("%H:%M:%S"), m_filename.c_str()); + GetCurrentTimeFormatted("%H:%M:%S"), m_filename.c_str()); // the name of the class from the last "\membersection" command: we assume // that the following "\func" or "\constfunc" always documents a method of - // this class (and it should always be like that in wxWindows documentation) + // this class (and it should always be like that in wxWidgets documentation) wxString classname; for ( const char *current = buf; current - buf < len; current++ ) { @@ -1166,7 +1502,7 @@ bool DocManager::ParseTeXFile(const wxString& filename) if ( !SkipSpaceUntil(¤t, '{') ) { wxLogWarning("file %s(%d): '{' expected after \\func, " "\\constfunc or \\membersection.", - m_filename.c_str(), m_line); + m_filename.c_str(), (int)m_line); continue; } @@ -1178,7 +1514,7 @@ bool DocManager::ParseTeXFile(const wxString& filename) const char *startClass = current; if ( !SkipUntil(¤t, ':') || *(current + 1) != ':' ) { wxLogWarning("file %s(%d): '::' expected after " - "\\membersection.", m_filename.c_str(), m_line); + "\\membersection.", m_filename.c_str(), (int)m_line); } else { classname = wxString(startClass, current - startClass); @@ -1193,7 +1529,7 @@ bool DocManager::ParseTeXFile(const wxString& filename) if ( !SkipUntil(¤t, '}') ) { wxLogWarning("file %s(%d): '}' expected after return type", - m_filename.c_str(), m_line); + m_filename.c_str(), (int)m_line); continue; } @@ -1202,9 +1538,9 @@ bool DocManager::ParseTeXFile(const wxString& filename) TeXUnfilter(&returnType); current++; - if ( !SkipSpaceUntil(¤t, '{') ) { + if ( !SkipSpaceUntil(¤t, '{') ) { wxLogWarning("file %s(%d): '{' expected after return type", - m_filename.c_str(), m_line); + m_filename.c_str(), (int)m_line); continue; } @@ -1213,7 +1549,7 @@ bool DocManager::ParseTeXFile(const wxString& filename) const char *funcEnd = current; if ( !SkipUntil(&funcEnd, '}') ) { wxLogWarning("file %s(%d): '}' expected after function name", - m_filename.c_str(), m_line); + m_filename.c_str(), (int)m_line); continue; } @@ -1222,8 +1558,8 @@ bool DocManager::ParseTeXFile(const wxString& filename) current = funcEnd + 1; // trim spaces from both sides - funcName.Trim(FALSE); - funcName.Trim(TRUE); + funcName.Trim(false); + funcName.Trim(true); // special cases: '$...$' may be used for LaTeX inline math, remove the // '$'s @@ -1242,7 +1578,7 @@ bool DocManager::ParseTeXFile(const wxString& filename) size_t len = strlen("\\destruct{"); if ( funcName(0, len) != "\\destruct{" ) { wxLogWarning("file %s(%d): \\destruct expected", - m_filename.c_str(), m_line); + m_filename.c_str(), (int)m_line); continue; } @@ -1252,7 +1588,7 @@ bool DocManager::ParseTeXFile(const wxString& filename) if ( !SkipSpaceUntil(¤t, '}') ) { wxLogWarning("file %s(%d): '}' expected after destructor", - m_filename.c_str(), m_line); + m_filename.c_str(), (int)m_line); continue; } @@ -1267,27 +1603,27 @@ bool DocManager::ParseTeXFile(const wxString& filename) if ( !SkipSpaceUntil(¤t, '{') || (current++, !SkipSpaceUntil(¤t, '\\')) ) { wxLogWarning("file %s(%d): '\\param' or '\\void' expected", - m_filename.c_str(), m_line); + m_filename.c_str(), (int)m_line); continue; } wxArrayString paramNames, paramTypes, paramValues; - bool isVararg = FALSE; + bool isVararg = false; current++; // skip '\\' lenMatch = TryMatch(current, "void"); if ( !lenMatch ) { lenMatch = TryMatch(current, "param"); - while ( lenMatch ) { + while ( lenMatch && (current - buf < len) ) { current += lenMatch; // now come {paramtype}{paramname} wxString paramType = ExtractStringBetweenBraces(¤t); - if ( !!paramType ) { + if ( !paramType.empty() ) { wxString paramText = ExtractStringBetweenBraces(¤t); - if ( !!paramText ) { + if ( !paramText.empty() ) { // the param declaration may contain default value wxString paramName = paramText.BeforeFirst('='), paramValue = paramText.AfterFirst('='); @@ -1306,7 +1642,7 @@ bool DocManager::ParseTeXFile(const wxString& filename) // vararg function? wxString paramText = ExtractStringBetweenBraces(¤t); if ( paramText == "..." ) { - isVararg = TRUE; + isVararg = true; } else { wxLogWarning("Parameters of '%s::%s' are in " @@ -1324,7 +1660,7 @@ bool DocManager::ParseTeXFile(const wxString& filename) } else { wxLogWarning("file %s(%d): ',' or '}' expected after " - "'\\param'", m_filename.c_str(), m_line); + "'\\param'", m_filename.c_str(), (int)m_line); continue; } @@ -1333,7 +1669,7 @@ bool DocManager::ParseTeXFile(const wxString& filename) // if we got here there was no '\\void', so must have some params if ( paramNames.IsEmpty() ) { wxLogWarning("file %s(%d): '\\param' or '\\void' expected", - m_filename.c_str(), m_line); + m_filename.c_str(), (int)m_line); continue; } @@ -1350,13 +1686,18 @@ bool DocManager::ParseTeXFile(const wxString& filename) paramsAll << paramTypes[param] << ' ' << paramNames[param]; } + wxString constStr; + if (foundCommand == ConstFunc) + constStr = _T(" const"); + wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'", - m_filename.c_str(), m_line, + m_filename.c_str(), + (int)m_line, returnType.c_str(), classname.c_str(), funcName.c_str(), paramsAll.c_str(), - foundCommand == ConstFunc ? " const" : ""); + constStr.c_str()); // store the info about the just found function ArrayMethodInfo *methods; @@ -1390,22 +1731,22 @@ bool DocManager::ParseTeXFile(const wxString& filename) delete [] buf; wxLogVerbose("%s: finished parsing doc file '%s'.\n", - GetCurrentTime("%H:%M:%S"), m_filename.c_str()); + GetCurrentTimeFormatted("%H:%M:%S"), m_filename.c_str()); - return TRUE; + return true; } bool DocManager::DumpDifferences(spContext *ctxTop) const { typedef MMemberListT::const_iterator MemberIndex; - bool foundDiff = FALSE; + bool foundDiff = false; // flag telling us whether the given class was found at all in the header size_t nClass, countClassesInDocs = m_classes.GetCount(); bool *classExists = new bool[countClassesInDocs]; for ( nClass = 0; nClass < countClassesInDocs; nClass++ ) { - classExists[nClass] = FALSE; + classExists[nClass] = false; } // ctxTop is normally an spFile @@ -1420,11 +1761,11 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const } spClass *ctxClass = (spClass *)ctx; - const wxString& nameClass = ctxClass->mName; + const wxString& nameClass = ctxClass->m_Name; int index = m_classes.Index(nameClass); if ( index == wxNOT_FOUND ) { - if ( !IgnoreClass(nameClass) ) { - foundDiff = TRUE; + if ( !m_ignoreNames.IgnoreClass(nameClass) ) { + foundDiff = true; wxLogError("Class '%s' is not documented at all.", nameClass.c_str()); @@ -1434,7 +1775,7 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const continue; } else { - classExists[index] = TRUE; + classExists[index] = true; } // array of method descriptions for this class @@ -1444,7 +1785,7 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const // flags telling if we already processed given function bool *methodExists = new bool[countMethods]; for ( nMethod = 0; nMethod < countMethods; nMethod++ ) { - methodExists[nMethod] = FALSE; + methodExists[nMethod] = false; } wxArrayString aOverloadedMethods; @@ -1456,7 +1797,7 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const continue; spOperation *ctxMethod = (spOperation *)ctx; - const wxString& nameMethod = ctxMethod->mName; + const wxString& nameMethod = ctxMethod->m_Name; // find all functions with the same name wxArrayInt aMethodsWithSameName; @@ -1466,8 +1807,8 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const } if ( aMethodsWithSameName.IsEmpty() && ctxMethod->IsPublic() ) { - if ( !IgnoreMethod(nameClass, nameMethod) ) { - foundDiff = TRUE; + if ( !m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) { + foundDiff = true; wxLogError("'%s::%s' is not documented.", nameClass.c_str(), @@ -1479,9 +1820,9 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const } else if ( aMethodsWithSameName.GetCount() == 1 ) { index = (size_t)aMethodsWithSameName[0u]; - methodExists[index] = TRUE; + methodExists[index] = true; - if ( IgnoreMethod(nameClass, nameMethod) ) + if ( m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) continue; if ( !ctxMethod->IsPublic() ) { @@ -1494,21 +1835,29 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const const MethodInfo& method = *(methods[index]); bool isVirtual = ctxMethod->mIsVirtual; - if ( isVirtual != method.HasFlag(MethodInfo::Virtual) ) { + if ( isVirtual != method.HasFlag(MethodInfo::Virtual) ) + { + wxString virtualStr; + if(isVirtual)virtualStr = _T("not "); + wxLogWarning("'%s::%s' is incorrectly documented as %s" "virtual.", nameClass.c_str(), nameMethod.c_str(), - isVirtual ? "not " : ""); + virtualStr.c_str()); } bool isConst = ctxMethod->mIsConstant; - if ( isConst != method.HasFlag(MethodInfo::Const) ) { + if ( isConst != method.HasFlag(MethodInfo::Const) ) + { + wxString constStr; + if(isConst)constStr = _T("not "); + wxLogWarning("'%s::%s' is incorrectly documented as %s" "constant.", nameClass.c_str(), nameMethod.c_str(), - isConst ? "not " : ""); + constStr.c_str()); } // check that the params match @@ -1519,7 +1868,7 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const "in the docs: should be %d instead of %d.", nameClass.c_str(), nameMethod.c_str(), - params.size(), method.GetParamCount()); + (int)params.size(), (int)method.GetParamCount()); } else { size_t nParam = 0; @@ -1533,58 +1882,59 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const spParameter *ctxParam = (spParameter *)ctx; const ParamInfo& param = method.GetParam(nParam); - if ( param.GetName() != ctxParam->mName ) { - foundDiff = TRUE; + if ( m_checkParamNames && + (param.GetName() != ctxParam->m_Name.c_str()) ) { + foundDiff = true; wxLogError("Parameter #%d of '%s::%s' should be " "'%s' and not '%s'.", - nParam + 1, + (int)(nParam + 1), nameClass.c_str(), nameMethod.c_str(), - ctxParam->mName.c_str(), + ctxParam->m_Name.c_str(), param.GetName().c_str()); continue; } - if ( param.GetType() != ctxParam->mType ) { - foundDiff = TRUE; + if ( param.GetType() != ctxParam->m_Type ) { + foundDiff = true; wxLogError("Type of parameter '%s' of '%s::%s' " "should be '%s' and not '%s'.", - ctxParam->mName.c_str(), + ctxParam->m_Name.c_str(), nameClass.c_str(), nameMethod.c_str(), - ctxParam->mType.c_str(), + ctxParam->m_Type.c_str(), param.GetType().GetName().c_str()); continue; } - if ( param.GetDefValue() != ctxParam->mInitVal ) { + if ( param.GetDefValue() != ctxParam->m_InitVal.c_str() ) { wxLogWarning("Default value of parameter '%s' of " "'%s::%s' should be '%s' and not " "'%s'.", - ctxParam->mName.c_str(), + ctxParam->m_Name.c_str(), nameClass.c_str(), nameMethod.c_str(), - ctxParam->mInitVal.c_str(), + ctxParam->m_InitVal.c_str(), param.GetDefValue().c_str()); } } } } 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 ) { // mark all methods with this name as existing for ( nMethod = 0; nMethod < countMethods; nMethod++ ) { if ( methods[nMethod]->GetName() == nameMethod ) - methodExists[nMethod] = TRUE; + methodExists[nMethod] = true; } aOverloadedMethods.Add(nameMethod); @@ -1602,8 +1952,8 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const for ( nMethod = 0; nMethod < countMethods; nMethod++ ) { if ( !methodExists[nMethod] ) { const wxString& nameMethod = methods[nMethod]->GetName(); - if ( !IgnoreMethod(nameClass, nameMethod) ) { - foundDiff = TRUE; + if ( !m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) { + foundDiff = true; wxLogError("'%s::%s' is documented but doesn't exist.", nameClass.c_str(), @@ -1618,7 +1968,7 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const // check that all classes we found in the docs really exist for ( nClass = 0; nClass < countClassesInDocs; nClass++ ) { if ( !classExists[nClass] ) { - foundDiff = TRUE; + foundDiff = true; wxLogError("Class '%s' is documented but doesn't exist.", m_classes[nClass].c_str()); @@ -1633,11 +1983,14 @@ bool DocManager::DumpDifferences(spContext *ctxTop) const 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); @@ -1647,15 +2000,15 @@ int DocManager::CompareIgnoreListEntries(IgnoreListEntry *first, return rc; } -bool DocManager::LoadIgnoreFile(const wxString& filename) +bool IgnoreNamesHandler::AddNamesFromFile(const wxString& filename) { wxFile file(filename, wxFile::read); if ( !file.IsOpened() ) - return FALSE; + return false; off_t len = file.Length(); if ( len == wxInvalidOffset ) - return FALSE; + return false; char *buf = new char[len + 1]; buf[len] = '\0'; @@ -1663,7 +2016,7 @@ bool DocManager::LoadIgnoreFile(const wxString& filename) if ( file.Read(buf, len) == wxInvalidOffset ) { delete [] buf; - return FALSE; + return false; } wxString line; @@ -1683,7 +2036,7 @@ bool DocManager::LoadIgnoreFile(const wxString& filename) } else { // entire class - m_ignore.Add(new IgnoreListEntry(line, "")); + m_ignore.Add(new IgnoreListEntry(line, wxEmptyString)); } } //else: comment @@ -1700,7 +2053,7 @@ bool DocManager::LoadIgnoreFile(const wxString& filename) delete [] buf; - return TRUE; + return true; } // ----------------------------------------------------------------------------- @@ -1733,8 +2086,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(); @@ -1749,21 +2138,33 @@ static wxString MakeHelpref(const char *argument) return helpref; } -static void TeXUnfilter(wxString* str) +static void TeXFilter(wxString* str) { - // FIXME may be done much more quickly - str->Trim(TRUE); - str->Trim(FALSE); + // TeX special which can be quoted (don't include backslash nor braces as + // we generate them + static wxRegEx reNonSpecialSpecials("[#$%&_]"), + reAccents("[~^]"); - str->Replace("\\&", "&"); - str->Replace("\\_", "_"); + // 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 TeXFilter(wxString* str) +static void TeXUnfilter(wxString* str) { // FIXME may be done much more quickly - str->Replace("&", "\\&"); - str->Replace("_", "\\_"); + str->Trim(true); + str->Trim(false); + + // undo TeXFilter + static wxRegEx reNonSpecialSpecials("\\\\([#$%&_{}])"), + reAccents("\\\\verb\\|([~^])\\|"); + + reNonSpecialSpecials.ReplaceAll(str, "\\1"); + reAccents.ReplaceAll(str, "\\1"); } static wxString GetAllComments(const spContext& ctx) @@ -1776,8 +2177,8 @@ static wxString GetAllComments(const spContext& ctx) wxString comment = (*i)->GetText(); // don't take comments like "// ----------" &c - comment.Trim(FALSE); - if ( !!comment && + comment.Trim(false); + if ( !comment.empty() && comment == wxString(comment[0u], comment.length() - 1) + '\n' ) comments << "\n"; else @@ -1787,7 +2188,7 @@ static wxString GetAllComments(const spContext& ctx) return comments; } -static const char *GetCurrentTime(const char *timeFormat) +static const char *GetCurrentTimeFormatted(const char *timeFormat) { static char s_timeBuffer[128]; time_t timeNow; @@ -1801,13 +2202,182 @@ static const char *GetCurrentTime(const char *timeFormat) return s_timeBuffer; } +static const wxString GetVersionString() +{ + wxString version = "$Revision$"; + wxRegEx("^\\$Revision$$").ReplaceFirst(&version, "\\1"); + return version; +} + /* $Log$ + Revision 1.44 2005/05/31 17:47:45 ABX + More warning and error fixes (work in progress with Tinderbox). + + Revision 1.43 2005/05/31 15:42:43 ABX + More warning and error fixes (work in progress with Tinderbox). + + Revision 1.42 2005/05/31 15:32:49 ABX + More warning and error fixes (work in progress with Tinderbox). + + Revision 1.41 2005/05/30 13:06:15 ABX + More warning and error fixes (work in progress with Tinderbox). + + Revision 1.40 2005/05/30 11:49:32 ABX + More warning and error fixes (work in progress with Tinderbox). + + Revision 1.39 2005/05/30 09:26:42 ABX + More warning and error fixes (work in progress with Tinderbox). + + Revision 1.38 2005/05/24 09:06:20 ABX + More fixes and wxWidgets coding standards. + + Revision 1.37 2005/05/23 15:22:08 ABX + Initial HelpGen source cleaning. + + Revision 1.36 2005/04/07 19:54:58 MW + Workarounds to allow compilation by Sun C++ 5.5 + + Revision 1.35 2004/12/12 11:03:31 VZ + give an error message if we're built in Unicode mode (in response to bug 1079224) + + Revision 1.34 2004/11/23 09:53:31 JS + Changed GPL to wxWindows Licence + + Revision 1.33 2004/11/12 03:30:07 RL + + Cruft cleanup from MJW, strip the tabs out of sound.cpp + + Revision 1.32 2004/11/10 21:02:58 VZ + new set of fixes for problems due to huge files support: drop wxFileSize_t, use wxFileOffset only, make wxInvalidOffset an int (main part of the patch 1063498) + + Revision 1.31 2004/10/05 15:38:29 ABX + Warning fixes found under hardest mode of OpenWatcom. Seems clean in Borland, MinGW and DMC. + + Revision 1.30 2004/06/18 19:25:50 ABX + Small step in making HelpGen up to date unicode application. + + Revision 1.29 2004/06/17 19:00:22 ABX + Warning fixes. Code cleanup. Whitespaces and tabs removed. + + Revision 1.28 2004/05/25 11:19:57 JS + More name changes + + Revision 1.27 2003/10/13 17:21:30 MBN + Compilation fixes. + + Revision 1.26 2003/09/29 15:18:35 MBN + (Blind) compilation fix for Sun compiler. + + Revision 1.25 2003/09/03 17:39:27 MBN + Compilation fixes. + + Revision 1.24 2003/08/13 22:59:37 VZ + compilation fix + + Revision 1.23 2003/06/13 17:05:43 VZ + quote '|' inside regexes (fixes dump mode); fixed crash due to strange HelpGenApp code + + 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 wxWidgets documentation from C++ headers */ /* vi: set tw=80 et ts=4 sw=4: */