X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1d1b48625e17b7eea75f8da111751a828946a29f..eeb67742cdf63068e82ec68e50ad2c9bb5ab613f:/utils/HelpGen/src/HelpGen.cpp?ds=inline diff --git a/utils/HelpGen/src/HelpGen.cpp b/utils/HelpGen/src/HelpGen.cpp deleted file mode 100644 index dbb6b655b8..0000000000 --- a/utils/HelpGen/src/HelpGen.cpp +++ /dev/null @@ -1,2382 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: HelpGen.cpp -// Purpose: Main program file for HelpGen -// Author: Vadim Zeitlin -// Modified by: -// Created: 06/01/99 -// RCS-ID: $Id$ -// Copyright: (c) 1999 VZ -// Licence: wxWindows Licence -///////////////////////////////////////////////////////////////////////////// - -/* - BUGS - - 1. wx/string.h confuses C++ parser terribly - 2. C++ parser doesn't know about virtual functions, nor static ones - 3. param checking is not done for vararg functions - 4. type comparison is dumb: it doesn't know that "char *" is the same - that "char []" nor that "const char *" is the same as "char const *" - - TODO (+ means fixed), see also the change log at the end of the file. - - (i) small fixes in the current version - - +1. Quote special TeX characters like '&' and '_' (=> derive from wxFile) - 2. Document typedefs - 3. Document global variables - 4. Document #defines - +5. Program options - 6. Include file name/line number in the "diff" messages? - +7. Support for vararg functions - - (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 - 2. GUI -*/ - -// ============================================================================= -// declarations -// ============================================================================= - -// ----------------------------------------------------------------------------- -// headers -// ----------------------------------------------------------------------------- - -// wxWidgets -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/log.h" - #include "wx/dynarray.h" - #include "wx/app.h" -#endif // WX_PRECOMP - -#include "wx/file.h" -#include "wx/regex.h" -#include "wx/hash.h" - -// C++ parsing classes -#include "cjparser.h" - -// standard headers -#include -#include - -// ----------------------------------------------------------------------------- -// 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); - -// return the whole \helpref{arg}{arg_label} string -static wxString MakeHelpref(const char *argument); - -// [un]quote special TeX characters (in place) -static void TeXFilter(wxString* str); -static void TeXUnfilter(wxString* str); // also trims spaces - -// get all comments associated with this context -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) -static const char *GetCurrentTimeFormatted(const char *timeFormat); - -// get the string containing the program version -static const wxString GetVersionString(); - -// ----------------------------------------------------------------------------- -// private classes -// ----------------------------------------------------------------------------- - -// 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() { } - - // 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); - - 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 -class HelpGenVisitor : public spVisitor -{ -public: - // ctor - HelpGenVisitor(const wxString& directoryOut, bool overwrite); - - virtual void VisitFile( spFile& fl ); - virtual void VisitClass( spClass& cl ); - virtual void VisitEnumeration( spEnumeration& en ); - virtual void VisitTypeDef( spTypeDef& td ); - virtual void VisitPreprocessorLine( spPreprocessorLine& pd ); - virtual void VisitAttribute( spAttribute& attr ); - virtual void VisitOperation( spOperation& op ); - virtual void VisitParameter( spParameter& param ); - - void EndVisit(); - - // get our `ignore' object - IgnoreNamesHandler& GetIgnoreHandler() { return m_ignoreNames; } - - // shut up g++ warning (ain't it stupid?) - virtual ~HelpGenVisitor() { } - -protected: - // (re)initialize the state - void Reset(); - - // insert documentation for enums/typedefs coming immediately before the - // class declaration into the class documentation - void InsertTypedefDocs(); - void InsertEnumDocs(); - - // write the headers for corresponding sections (only once) - void InsertDataStructuresHeader(); - void InsertMethodsHeader(); - - // 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? - wxTeXFile m_file; // file we're writing to now - - // state variables - bool m_inClass, // true after file successfully opened - m_inTypesSection, // enums & typedefs go there - m_inMethodSection, // functions go here - m_isFirstParam; // first parameter of current function? - - // 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, - 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&); -}; - -// documentation manager - a class which parses TeX files and remembers the -// functions documented in them and can later compare them with all functions -// found under ctxTop by C++ parser -class DocManager -{ -public: - DocManager(bool checkParamNames); - ~DocManager(); - - // 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 - // ----------------- - - // 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); - - // skip spaces: returns pointer to first non space character (also - // updates the value of m_line) - const char *SkipSpaces(const char *p) - { - while ( isspace(*p) ) { - if ( *p++ == '\n' ) - m_line++; - } - - return p; - } - - // 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 - // 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 - bool SkipSpaceUntil(const char **pp, char c); - - // extract the string between {} and modify '*pp' to point at the - // character immediately after the closing '}'. The returned string is empty - // on error. - wxString ExtractStringBetweenBraces(const char **pp); - - // the current file and line while we're in ParseTeXFile (for error - // messages) - wxString m_filename; - size_t m_line; - - // functions and classes to ignore during diff - // ------------------------------------------- - - 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 - { - public: - TypeInfo(const wxString& type) : m_type(type) { } - - bool operator==(const wxString& type) const { return m_type == type; } - bool operator!=(const wxString& type) const { return m_type != type; } - - const wxString& GetName() const { return m_type; } - - private: - wxString m_type; - }; - - friend class ParamInfo; // for access to TypeInfo - - // info abotu a function parameter - class ParamInfo - { - public: - ParamInfo(const wxString& type, - const wxString& name, - const wxString& value) - : m_type(type), m_name(name), m_value(value) - { - } - - const TypeInfo& GetType() const { return m_type; } - const wxString& GetName() const { return m_name; } - const wxString& GetDefValue() const { return m_value; } - - private: - TypeInfo m_type; // type of parameter - wxString m_name; // name - wxString m_value; // default value - }; - -public: // FIXME: macro requires it - WX_DEFINE_ARRAY_PTR(ParamInfo *, ArrayParamInfo); - - // info about a function - struct MethodInfo - { - public: - enum MethodFlags - { - Const = 0x0001, - Virtual = 0x0002, - Pure = 0x0004, - Static = 0x0008, - Vararg = 0x0010 - }; - - MethodInfo(const wxString& type, - const wxString& name, - const ArrayParamInfo& params) - : m_typeRet(type), m_name(name), m_params(params) - { - m_flags = 0; - } - - void SetFlag(MethodFlags flag) { m_flags |= flag; } - - const TypeInfo& GetType() const { return m_typeRet; } - const wxString& GetName() const { return m_name; } - const ParamInfo& GetParam(size_t n) const { return *(m_params[n]); } - size_t GetParamCount() const { return m_params.GetCount(); } - - bool HasFlag(MethodFlags flag) const { return (m_flags & flag) != 0; } - - ~MethodInfo() { WX_CLEAR_ARRAY(m_params); } - - private: - TypeInfo m_typeRet; // return type - wxString m_name; - int m_flags; // bit mask of the value from the enum above - - ArrayParamInfo m_params; - }; - - 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; - - // 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.AfterLast('/'); -#ifdef __WXMSW__ - if ( !basename ) - basename = prog.AfterLast('\\'); -#endif - if ( !basename ) - basename = prog; - - wxLogMessage( -"usage: %s [global options] [mode options] \n" -"\n" -" where global options are:\n" -" -q be quiet\n" -" -v be verbose\n" -" -H give this usage message\n" -" -V print the version info\n" -" -i file file with classes/function to ignore\n" -"\n" -" where mode is one of: dump, diff\n" -"\n" -" dump means generate .tex files for TeX2RTF converter from specified\n" -" headers files, mode options are:\n" -" -f overwrite existing files\n" -" -o outdir directory for generated files\n" -"\n" -" diff means compare the set of methods documented .tex file with the\n" -" methods declared in the header:\n" -" %s diff .\n" -" mode specific options are:\n" -" -p do check parameter names (not done by default)\n" -"\n", basename.c_str(), basename.c_str()); - - exit(1); -} - -int main(int argc, char **argv) -{ - g_argv = argv; - - wxInitializer initializer; - if ( !initializer ) - { - fprintf(stderr, "Failed to initialize the wxWidgets library, aborting."); - - return -1; - } - - enum - { - Mode_None, - Mode_Dump, - Mode_Diff - } mode = Mode_None; - - if ( argc < 2 ) { - usage(); - } - - wxArrayString filesH, filesTeX; - 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 - if ( argv[current][0] == '-' ) { - if ( argv[current][2] == '\0' ) { - switch ( argv[current][1] ) { - case 'v': - // be verbose - wxLog::GetActiveTarget()->SetVerbose(); - continue; - - case 'q': - // be quiet - 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("-p is only valid with diff."); - - break; - } - - paramNames = true; - continue; - - case 'f': - if ( mode != Mode_Dump ) { - wxLogError("-f is only valid with dump."); - - break; - } - - overwrite = true; - continue; - - case 'o': - if ( mode != Mode_Dump ) { - wxLogError("-o is only valid with dump."); - - break; - } - - current++; - if ( current >= argc ) { - wxLogError("-o option requires an argument."); - - break; - } - - directoryOut = argv[current]; - if ( !directoryOut.empty() ) { - // terminate with a '/' if it doesn't have it - switch ( directoryOut.Last().GetValue() ) { - case '/': -#ifdef __WXMSW__ - case '\\': -#endif - break; - - default: - directoryOut += '/'; - } - } - //else: it's empty, do nothing - - 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 - - usage(); - } - else { - if ( mode == Mode_None ) { - if ( strcmp(argv[current], "diff") == 0 ) - mode = Mode_Diff; - else if ( strcmp(argv[current], "dump") == 0 ) - mode = Mode_Dump; - else { - wxLogError("unknown mode '%s'.", argv[current]); - - usage(); - } - } - else { - if ( mode == Mode_Dump || filesH.IsEmpty() ) { - filesH.Add(argv[current]); - } - else { - // 2nd files and further are TeX files in diff mode - wxASSERT( mode == Mode_Diff ); - - filesTeX.Add(argv[current]); - } - } - } - } - - // create a parser object and a visitor derivation - CJSourceParser parser; - HelpGenVisitor visitor(directoryOut, overwrite); - if ( !ignoreFile.empty() && mode == Mode_Dump ) - visitor.GetIgnoreHandler().AddNamesFromFile(ignoreFile); - - spContext *ctxTop = NULL; - - // parse all header files - size_t nFiles = filesH.GetCount(); - for ( size_t n = 0; n < nFiles; n++ ) { - wxString header = filesH[n]; - ctxTop = parser.ParseFile(header); - if ( !ctxTop ) { - wxLogWarning("Header file '%s' couldn't be processed.", - header.c_str()); - } - else if ( mode == Mode_Dump ) { - ((spFile *)ctxTop)->m_FileName = header; - visitor.VisitAll(*ctxTop); - visitor.EndVisit(); - } - -#ifdef __WXDEBUG__ - if ( 0 && ctxTop ) - ctxTop->Dump(wxEmptyString); -#endif // __WXDEBUG__ - } - - // parse all TeX files - if ( mode == Mode_Diff ) { - if ( !ctxTop ) { - wxLogError("Can't complete diff."); - - // failure - return false; - } - - DocManager docman(paramNames); - - size_t nFiles = filesTeX.GetCount(); - for ( size_t n = 0; n < nFiles; n++ ) { - wxString file = filesTeX[n]; - if ( !docman.ParseTeXFile(file) ) { - wxLogWarning("TeX file '%s' couldn't be processed.", - file.c_str()); - } - } - - if ( !ignoreFile.empty() ) - docman.GetIgnoreHandler().AddNamesFromFile(ignoreFile); - - docman.DumpDifferences(ctxTop); - } - - return 0; -} - -// ----------------------------------------------------------------------------- -// HelpGenVisitor implementation -// ----------------------------------------------------------------------------- - -HelpGenVisitor::HelpGenVisitor(const wxString& directoryOut, - bool overwrite) - : m_directoryOut(directoryOut) -{ - m_overwrite = overwrite; - - Reset(); -} - -void HelpGenVisitor::Reset() -{ - m_inClass = - m_inTypesSection = - m_inMethodSection = false; - - m_classname = - m_funcName = - m_textFunc = - m_textStoredTypedefs = - m_textStoredFunctionComment = wxEmptyString; - - m_arrayFuncDocs.Empty(); - - m_storedEnums.Empty(); - m_storedEnumsVerb.Empty(); - m_headers.Empty(); -} - -void HelpGenVisitor::InsertTypedefDocs() -{ - m_file.WriteTeX(m_textStoredTypedefs); - m_textStoredTypedefs.Empty(); -} - -void HelpGenVisitor::InsertEnumDocs() -{ - size_t count = m_storedEnums.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - m_file.WriteTeX(m_storedEnums[n]); - m_file.WriteVerbatim(m_storedEnumsVerb[n] + '\n'); - } - - m_storedEnums.Empty(); - m_storedEnumsVerb.Empty(); -} - -void HelpGenVisitor::InsertDataStructuresHeader() -{ - if ( !m_inTypesSection ) { - m_inTypesSection = true; - - m_file.WriteVerbatim("\\wxheading{Data structures}\n\n"); - } -} - -void HelpGenVisitor::InsertMethodsHeader() -{ - if ( !m_inMethodSection ) { - m_inMethodSection = true; - - m_file.WriteVerbatim( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n"); - } -} - -void HelpGenVisitor::CloseFunction() -{ - if ( !m_funcName.empty() ) { - if ( m_isFirstParam ) { - // no params found - m_textFunc << "\\void"; - } - - m_textFunc << "}\n\n"; - - if ( !m_textStoredFunctionComment.empty() ) { - m_textFunc << m_textStoredFunctionComment << '\n'; - } - - m_arrayFuncDocs.Add(new FunctionDocEntry(m_funcName, m_textFunc)); - - m_funcName.clear(); - } -} - -void HelpGenVisitor::CloseClass() -{ - CloseFunction(); - - if ( m_inClass ) - { - size_t count = m_arrayFuncDocs.GetCount(); - if ( count ) - { - size_t n; - FunctionDocEntry::classname = m_classname; - - m_arrayFuncDocs.Sort(FunctionDocEntry::Compare); - - // Now examine each first line and if it's been seen, cut it - // off (it's a duplicate \membersection) - wxHashTable membersections(wxKEY_STRING); - - for ( n = 0; n < count; n++ ) - { - wxString section(m_arrayFuncDocs[n].text); - - // Strip leading whitespace - int pos = section.Find(_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.", - GetCurrentTimeFormatted("%H:%M:%S")); -} - -void HelpGenVisitor::VisitFile( spFile& file ) -{ - m_fileHeader = file.m_FileName; - wxLogVerbose("%s: started generating docs for classes from file '%s'...", - 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; - if ( name(0, 2) == "wx" ) { - filename << name.c_str() + 2; - } - else { - filename << name; - } - - filename.MakeLower(); - filename += ".tex"; - filename.Prepend(m_directoryOut); - - if ( !m_overwrite && wxFile::Exists(filename) ) { - wxLogError("Won't overwrite existing file '%s' - please use '-f'.", - filename.c_str()); - - return; - } - - m_inClass = m_file.Open(filename, wxFile::write); - if ( !m_inClass ) { - wxLogError("Can't generate documentation for the class '%s'.", - name.c_str()); - - return; - } - - m_inMethodSection = - 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; - - // 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 wxWidgets headers and class names - static const char *headers[] = { - "object", - "defs", - "string", - "dynarray", - "file", - "time", - }; - - // NULL here means not to insert anything in "See also" for the - // corresponding header - static const char *classes[] = { - NULL, - NULL, - NULL, - NULL, - "wxFile", - "wxTime", - }; - - wxASSERT_MSG( WXSIZEOF(headers) == WXSIZEOF(classes), - "arrays must be in sync!" ); - - wxArrayInt interestingClasses; - - size_t count = m_headers.Count(), index; - for ( size_t n = 0; n < count; n++ ) { - wxString baseHeaderName = m_headers[n].Before('.'); - if ( baseHeaderName(0, 3) != "wx/" ) - continue; - - baseHeaderName.erase(0, 3); - for ( index = 0; index < WXSIZEOF(headers); index++ ) { - if ( wxStricmp(baseHeaderName, headers[index]) == 0 ) - break; - } - - if ( (index < WXSIZEOF(headers)) && classes[index] ) { - // interesting header - interestingClasses.Add(index); - } - } - - if ( !interestingClasses.IsEmpty() ) { - // do generate "See also" clause - totalText << "\\wxheading{See also:}\n\n"; - - count = interestingClasses.Count(); - for ( index = 0; index < count; index++ ) { - if ( index > 0 ) - totalText << ", "; - - totalText << MakeHelpref(classes[interestingClasses[index]]); - } - - totalText << "\n\n"; - } - } - - // the comment before the class generally explains what is it for so put it - // in place of the class description - if ( cl.HasComments() ) { - wxString comment = GetAllComments(cl); - - totalText << '\n' << comment << '\n'; - } - - // derived from section - wxString derived = "\\wxheading{Derived from}\n\n"; - - const StrListT& baseClasses = cl.m_SuperClassNames; - if ( baseClasses.size() == 0 ) { - derived << "No base class"; - } - else { - bool first = true; - for ( StrListT::const_iterator i = baseClasses.begin(); - i != baseClasses.end(); - i++ ) { - if ( !first ) { - // separate from the previous one - derived << "\\\\\n"; - } - else { - first = false; - } - - wxString baseclass = *i; - derived << "\\helpref{" << baseclass << "}"; - derived << "{" << baseclass.MakeLower() << "}"; - } - } - 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); - - // if there were any enums/typedefs before, insert their documentation now - InsertDataStructuresHeader(); - InsertTypedefDocs(); - InsertEnumDocs(); - - //m_file.Flush(); -} - -void HelpGenVisitor::VisitEnumeration( spEnumeration& en ) -{ - CloseFunction(); - - if ( m_inMethodSection ) { - // FIXME that's a bug, but tell the user aboit it nevertheless... we - // should be smart enough to process even the enums which come after the - // functions - wxLogWarning("enum '%s' ignored, please put it before the class " - "methods.", en.GetName().c_str()); - return; - } - - // simply copy the enum text in the docs - 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 ) { - m_storedEnums.Add(enumeration); - m_storedEnumsVerb.Add(enumerationVerb); - } - else { - // write the header for this section if not done yet - InsertDataStructuresHeader(); - - m_file.WriteTeX(enumeration); - m_file.WriteVerbatim(enumerationVerb); - m_file.WriteVerbatim('\n'); - } -} - -void HelpGenVisitor::VisitTypeDef( spTypeDef& td ) -{ - CloseFunction(); - - if ( m_inMethodSection ) { - // FIXME that's a bug, but tell the user aboit it nevertheless... - wxLogWarning("typedef '%s' ignored, please put it before the class " - "methods.", td.GetName().c_str()); - return; - } - - wxString typedefdoc; - 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.empty() ) { - m_textStoredTypedefs << '\n'; - } - - m_textStoredTypedefs << typedefdoc; - } - else { - // write the header for this section if not done yet - InsertDataStructuresHeader(); - - typedefdoc << '\n'; - m_file.WriteTeX(typedefdoc); - } -} - -void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine& pd ) -{ - switch ( pd.GetStatementType() ) { - case SP_PREP_DEF_INCLUDE_FILE: - m_headers.Add(pd.CPP_GetIncludedFileNeme()); - break; - - case SP_PREP_DEF_DEFINE_SYMBOL: - // TODO decide if it's a constant and document it if it is - break; - } -} - -void HelpGenVisitor::VisitAttribute( spAttribute& attr ) -{ - CloseFunction(); - - // only document the public member variables - if ( !m_inClass || !attr.IsPublic() ) - return; - - wxLogWarning("Ignoring member variable '%s'.", attr.GetName().c_str()); -} - -void HelpGenVisitor::VisitOperation( spOperation& op ) -{ - CloseFunction(); - - 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; - } - - if ( op.mVisibility == SP_VIS_PRIVATE ) { - // FIXME should we document protected functions? - 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_funcName = funcname; - m_isFirstParam = true; - - m_textStoredFunctionComment = GetAllComments(op); - - // start function documentation - wxString totalText; - - // check for the special case of dtor - wxString dtor; - if ( (funcname[0u] == '~') && (m_classname == funcname.c_str() + 1) ) { - dtor.Printf("\\destruct{%s}", m_classname.c_str()); - funcname = dtor; - } - - 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_funcName.empty() ) - return; - - if ( m_isFirstParam ) { - m_isFirstParam = false; - } - else { - m_textFunc << ", "; - } - - m_textFunc << "\\param{" << param.m_Type << " }{" << param.GetName(); - wxString defvalue = param.m_InitVal; - if ( !defvalue.empty() ) { - m_textFunc << " = " << defvalue; - } - - m_textFunc << '}'; -} - -// --------------------------------------------------------------------------- -// DocManager -// --------------------------------------------------------------------------- - -DocManager::DocManager(bool checkParamNames) -{ - m_checkParamNames = checkParamNames; -} - -size_t DocManager::TryMatch(const char *str, const char *match) -{ - size_t lenMatch = 0; - while ( str[lenMatch] == match[lenMatch] ) { - lenMatch++; - - if ( match[lenMatch] == '\0' ) - return lenMatch; - } - - return 0; -} - -bool DocManager::SkipUntil(const char **pp, char c) -{ - const char *p = *pp; - while ( *p != c ) { - if ( *p == '\0' ) - break; - - if ( *p == '\n' ) - m_line++; - - p++; - } - - *pp = p; - - return *p == c; -} - -bool DocManager::SkipSpaceUntil(const char **pp, char c) -{ - const char *p = *pp; - while ( *p != c ) { - if ( !isspace(*p) || *p == '\0' ) - break; - - if ( *p == '\n' ) - m_line++; - - p++; - } - - *pp = p; - - return *p == c; -} - -wxString DocManager::ExtractStringBetweenBraces(const char **pp) -{ - wxString result; - - if ( !SkipSpaceUntil(pp, '{') ) { - wxLogWarning("file %s(%d): '{' expected after '\\param'", - m_filename.c_str(), (int)m_line); - - } - else { - const char *startParam = ++*pp; // skip '{' - - if ( !SkipUntil(pp, '}') ) { - wxLogWarning("file %s(%d): '}' expected after '\\param'", - m_filename.c_str(), (int)m_line); - } - else { - result = wxString(startParam, (*pp)++ - startParam); - } - } - - return result; -} - -bool DocManager::ParseTeXFile(const wxString& filename) -{ - m_filename = filename; - - wxFile file(m_filename, wxFile::read); - if ( !file.IsOpened() ) - return false; - - off_t len = file.Length(); - if ( len == wxInvalidOffset ) - return false; - - char *buf = new char[len + 1]; - buf[len] = '\0'; - - if ( file.Read(buf, len) == wxInvalidOffset ) { - delete [] buf; - - return false; - } - - // reinit everything - m_line = 1; - - wxLogVerbose("%s: starting to parse doc file '%s'.", - 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 wxWidgets documentation) - wxString classname; - - for ( const char *current = buf; current - buf < len; current++ ) { - // FIXME parsing is awfully inefficient - - if ( *current == '%' ) { - // comment, skip until the end of line - current++; - SkipUntil(¤t, '\n'); - - continue; - } - - // all the command we're interested in start with '\\' - while ( *current != '\\' && *current != '\0' ) { - if ( *current++ == '\n' ) - m_line++; - } - - if ( *current == '\0' ) { - // no more TeX commands left - break; - } - - current++; // skip '\\' - - enum - { - Nothing, - Func, - ConstFunc, - MemberSect - } foundCommand = Nothing; - - size_t lenMatch = TryMatch(current, "func"); - if ( lenMatch ) { - foundCommand = Func; - } - else { - lenMatch = TryMatch(current, "constfunc"); - if ( lenMatch ) - foundCommand = ConstFunc; - else { - lenMatch = TryMatch(current, "membersection"); - - if ( lenMatch ) - foundCommand = MemberSect; - } - } - - if ( foundCommand == Nothing ) - continue; - - current += lenMatch; - - if ( !SkipSpaceUntil(¤t, '{') ) { - wxLogWarning("file %s(%d): '{' expected after \\func, " - "\\constfunc or \\membersection.", - m_filename.c_str(), (int)m_line); - - continue; - } - - current++; - - if ( foundCommand == MemberSect ) { - // what follows has the form :: - const char *startClass = current; - if ( !SkipUntil(¤t, ':') || *(current + 1) != ':' ) { - wxLogWarning("file %s(%d): '::' expected after " - "\\membersection.", m_filename.c_str(), (int)m_line); - } - else { - classname = wxString(startClass, current - startClass); - TeXUnfilter(&classname); - } - - continue; - } - - // extract the return type - const char *startRetType = current; - - if ( !SkipUntil(¤t, '}') ) { - wxLogWarning("file %s(%d): '}' expected after return type", - m_filename.c_str(), (int)m_line); - - continue; - } - - wxString returnType = wxString(startRetType, current - startRetType); - TeXUnfilter(&returnType); - - current++; - if ( !SkipSpaceUntil(¤t, '{') ) { - wxLogWarning("file %s(%d): '{' expected after return type", - m_filename.c_str(), (int)m_line); - - continue; - } - - current++; - const char *funcEnd = current; - if ( !SkipUntil(&funcEnd, '}') ) { - wxLogWarning("file %s(%d): '}' expected after function name", - m_filename.c_str(), (int)m_line); - - continue; - } - - wxString funcName = wxString(current, funcEnd - current); - current = funcEnd + 1; - - // trim spaces from both sides - funcName.Trim(false); - funcName.Trim(true); - - // special cases: '$...$' may be used for LaTeX inline math, remove the - // '$'s - if ( funcName.Find('$') != wxNOT_FOUND ) { - wxString name; - for ( const char *p = funcName.c_str(); *p != '\0'; p++ ) { - if ( *p != '$' && !isspace(*p) ) - name += *p; - } - - funcName = name; - } - - // \destruct{foo} is really ~foo - if ( funcName[0u] == '\\' ) { - size_t len = strlen("\\destruct{"); - if ( funcName(0, len) != "\\destruct{" ) { - wxLogWarning("file %s(%d): \\destruct expected", - m_filename.c_str(), (int)m_line); - - continue; - } - - funcName.erase(0, len); - funcName.Prepend('~'); - - if ( !SkipSpaceUntil(¤t, '}') ) { - wxLogWarning("file %s(%d): '}' expected after destructor", - m_filename.c_str(), (int)m_line); - - continue; - } - - funcEnd++; // there is an extra '}' to count - } - - TeXUnfilter(&funcName); - - // extract params - current = funcEnd + 1; // skip '}' - if ( !SkipSpaceUntil(¤t, '{') || - (current++, !SkipSpaceUntil(¤t, '\\')) ) { - wxLogWarning("file %s(%d): '\\param' or '\\void' expected", - m_filename.c_str(), (int)m_line); - - continue; - } - - wxArrayString paramNames, paramTypes, paramValues; - - bool isVararg = false; - - current++; // skip '\\' - lenMatch = TryMatch(current, "void"); - if ( !lenMatch ) { - lenMatch = TryMatch(current, "param"); - while ( lenMatch && (current - buf < len) ) { - current += lenMatch; - - // now come {paramtype}{paramname} - wxString paramType = ExtractStringBetweenBraces(¤t); - if ( !paramType.empty() ) { - wxString paramText = ExtractStringBetweenBraces(¤t); - if ( !paramText.empty() ) { - // the param declaration may contain default value - wxString paramName = paramText.BeforeFirst('='), - paramValue = paramText.AfterFirst('='); - - // sanitize all strings - TeXUnfilter(¶mValue); - TeXUnfilter(¶mName); - TeXUnfilter(¶mType); - - paramValues.Add(paramValue); - paramNames.Add(paramName); - paramTypes.Add(paramType); - } - } - else { - // vararg function? - wxString paramText = ExtractStringBetweenBraces(¤t); - if ( paramText == "..." ) { - isVararg = true; - } - else { - wxLogWarning("Parameters of '%s::%s' are in " - "incorrect form.", - classname.c_str(), funcName.c_str()); - } - } - - // what's next? - current = SkipSpaces(current); - if ( *current == ',' || *current == '}' ) { - current = SkipSpaces(++current); - - lenMatch = TryMatch(current, "\\param"); - } - else { - wxLogWarning("file %s(%d): ',' or '}' expected after " - "'\\param'", m_filename.c_str(), (int)m_line); - - continue; - } - } - - // 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(), (int)m_line); - - continue; - } - } - - // verbose diagnostic output - wxString paramsAll; - size_t param, paramCount = paramNames.GetCount(); - for ( param = 0; param < paramCount; param++ ) { - if ( param != 0 ) { - paramsAll << ", "; - } - - 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(), - (int)m_line, - returnType.c_str(), - classname.c_str(), - funcName.c_str(), - paramsAll.c_str(), - constStr.c_str()); - - // store the info about the just found function - ArrayMethodInfo *methods; - int index = m_classes.Index(classname); - if ( index == wxNOT_FOUND ) { - m_classes.Add(classname); - - methods = new ArrayMethodInfo; - m_methods.Add(methods); - } - else { - methods = m_methods[(size_t)index]; - } - - ArrayParamInfo params; - for ( param = 0; param < paramCount; param++ ) { - params.Add(new ParamInfo(paramTypes[param], - paramNames[param], - paramValues[param])); - } - - MethodInfo *method = new MethodInfo(returnType, funcName, params); - if ( foundCommand == ConstFunc ) - method->SetFlag(MethodInfo::Const); - if ( isVararg ) - method->SetFlag(MethodInfo::Vararg); - - methods->Add(method); - } - - delete [] buf; - - wxLogVerbose("%s: finished parsing doc file '%s'.\n", - GetCurrentTimeFormatted("%H:%M:%S"), m_filename.c_str()); - - return true; -} - -bool DocManager::DumpDifferences(spContext *ctxTop) const -{ - typedef MMemberListT::const_iterator MemberIndex; - - 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; - } - - // ctxTop is normally an spFile - wxASSERT( ctxTop->GetContextType() == SP_CTX_FILE ); - - const MMemberListT& classes = ctxTop->GetMembers(); - for ( MemberIndex i = classes.begin(); i != classes.end(); i++ ) { - spContext *ctx = *i; - if ( ctx->GetContextType() != SP_CTX_CLASS ) { - // TODO process also global functions, macros, ... - continue; - } - - spClass *ctxClass = (spClass *)ctx; - const wxString& nameClass = ctxClass->m_Name; - int index = m_classes.Index(nameClass); - if ( index == wxNOT_FOUND ) { - if ( !m_ignoreNames.IgnoreClass(nameClass) ) { - foundDiff = true; - - wxLogError("Class '%s' is not documented at all.", - nameClass.c_str()); - } - - // it makes no sense to check for its functions - continue; - } - else { - classExists[index] = true; - } - - // array of method descriptions for this class - const ArrayMethodInfo& methods = *(m_methods[index]); - size_t nMethod, countMethods = methods.GetCount(); - - // flags telling if we already processed given function - bool *methodExists = new bool[countMethods]; - for ( nMethod = 0; nMethod < countMethods; nMethod++ ) { - methodExists[nMethod] = false; - } - - wxArrayString aOverloadedMethods; - - const MMemberListT& functions = ctxClass->GetMembers(); - for ( MemberIndex j = functions.begin(); j != functions.end(); j++ ) { - ctx = *j; - if ( ctx->GetContextType() != SP_CTX_OPERATION ) - continue; - - spOperation *ctxMethod = (spOperation *)ctx; - const wxString& nameMethod = ctxMethod->m_Name; - - // find all functions with the same name - wxArrayInt aMethodsWithSameName; - for ( nMethod = 0; nMethod < countMethods; nMethod++ ) { - if ( methods[nMethod]->GetName() == nameMethod ) - aMethodsWithSameName.Add(nMethod); - } - - if ( aMethodsWithSameName.IsEmpty() && ctxMethod->IsPublic() ) { - if ( !m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) { - foundDiff = true; - - wxLogError("'%s::%s' is not documented.", - nameClass.c_str(), - nameMethod.c_str()); - } - - // don't check params - continue; - } - else if ( aMethodsWithSameName.GetCount() == 1 ) { - index = (size_t)aMethodsWithSameName[0u]; - methodExists[index] = true; - - if ( m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) - continue; - - if ( !ctxMethod->IsPublic() ) { - wxLogWarning("'%s::%s' is documented but not public.", - nameClass.c_str(), - nameMethod.c_str()); - } - - // check that the flags match - const MethodInfo& method = *(methods[index]); - - bool isVirtual = ctxMethod->mIsVirtual; - 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(), - virtualStr.c_str()); - } - - bool isConst = ctxMethod->mIsConstant; - 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(), - constStr.c_str()); - } - - // check that the params match - const MMemberListT& params = ctxMethod->GetMembers(); - - if ( params.size() != method.GetParamCount() ) { - wxLogError("Incorrect number of parameters for '%s::%s' " - "in the docs: should be %d instead of %d.", - nameClass.c_str(), - nameMethod.c_str(), - (int)params.size(), (int)method.GetParamCount()); - } - else { - size_t nParam = 0; - for ( MemberIndex k = params.begin(); - k != params.end(); - k++, nParam++ ) { - ctx = *k; - - // what else can a function have? - wxASSERT( ctx->GetContextType() == SP_CTX_PARAMETER ); - - spParameter *ctxParam = (spParameter *)ctx; - const ParamInfo& param = method.GetParam(nParam); - if ( m_checkParamNames && - (param.GetName() != ctxParam->m_Name.c_str()) ) { - foundDiff = true; - - wxLogError("Parameter #%d of '%s::%s' should be " - "'%s' and not '%s'.", - (int)(nParam + 1), - nameClass.c_str(), - nameMethod.c_str(), - ctxParam->m_Name.c_str(), - param.GetName().c_str()); - - continue; - } - - if ( param.GetType() != ctxParam->m_Type ) { - foundDiff = true; - - wxLogError("Type of parameter '%s' of '%s::%s' " - "should be '%s' and not '%s'.", - ctxParam->m_Name.c_str(), - nameClass.c_str(), - nameMethod.c_str(), - ctxParam->m_Type.c_str(), - param.GetType().GetName().c_str()); - - continue; - } - - if ( param.GetDefValue() != ctxParam->m_InitVal.c_str() ) { - wxLogWarning("Default value of parameter '%s' of " - "'%s::%s' should be '%s' and not " - "'%s'.", - ctxParam->m_Name.c_str(), - nameClass.c_str(), - nameMethod.c_str(), - ctxParam->m_InitVal.c_str(), - param.GetDefValue().c_str()); - } - } - } - } - else { - // TODO OVER add real support for overloaded methods - - 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; - } - - aOverloadedMethods.Add(nameMethod); - - wxLogVerbose("'%s::%s' is overloaded and I'm too " - "stupid to find the right match - skipping " - "the param and flags checks.", - nameClass.c_str(), - nameMethod.c_str()); - } - //else: warning already given - } - } - - for ( nMethod = 0; nMethod < countMethods; nMethod++ ) { - if ( !methodExists[nMethod] ) { - const wxString& nameMethod = methods[nMethod]->GetName(); - if ( !m_ignoreNames.IgnoreMethod(nameClass, nameMethod) ) { - foundDiff = true; - - wxLogError("'%s::%s' is documented but doesn't exist.", - nameClass.c_str(), - nameMethod.c_str()); - } - } - } - - delete [] methodExists; - } - - // check that all classes we found in the docs really exist - for ( nClass = 0; nClass < countClassesInDocs; nClass++ ) { - if ( !classExists[nClass] ) { - foundDiff = true; - - wxLogError("Class '%s' is documented but doesn't exist.", - m_classes[nClass].c_str()); - } - } - - delete [] classExists; - - return !foundDiff; -} - -DocManager::~DocManager() -{ - WX_CLEAR_ARRAY(m_methods); -} - -// --------------------------------------------------------------------------- -// IgnoreNamesHandler implementation -// --------------------------------------------------------------------------- - -int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry *first, - IgnoreListEntry *second) -{ - // first compare the classes - int rc = first->m_classname.Cmp(second->m_classname); - if ( rc == 0 ) - rc = first->m_funcname.Cmp(second->m_funcname); - - return rc; -} - -bool IgnoreNamesHandler::AddNamesFromFile(const wxString& filename) -{ - wxFile file(filename, wxFile::read); - if ( !file.IsOpened() ) - return false; - - off_t len = file.Length(); - if ( len == wxInvalidOffset ) - return false; - - char *buf = new char[len + 1]; - buf[len] = '\0'; - - if ( file.Read(buf, len) == wxInvalidOffset ) { - delete [] buf; - - return false; - } - - wxString line; - for ( const char *current = buf; ; current++ ) { -#ifdef __WXMSW__ - // skip DOS line separator - if ( *current == '\r' ) - current++; -#endif // wxMSW - - if ( *current == '\n' || *current == '\0' ) { - if ( line[0u] != '#' ) { - if ( line.Find(':') != wxNOT_FOUND ) { - wxString classname = line.BeforeFirst(':'), - funcname = line.AfterLast(':'); - m_ignore.Add(new IgnoreListEntry(classname, funcname)); - } - else { - // entire class - m_ignore.Add(new IgnoreListEntry(line, wxEmptyString)); - } - } - //else: comment - - if ( *current == '\0' ) - break; - - line.Empty(); - } - else { - line += *current; - } - } - - delete [] buf; - - return true; -} - -// ----------------------------------------------------------------------------- -// global function implementation -// ----------------------------------------------------------------------------- - -static wxString MakeLabel(const char *classname, const char *funcname) -{ - wxString label(classname); - if ( funcname && funcname[0] == '\\' ) { - // we may have some special TeX macro - so far only \destruct exists, - // but may be later others will be added - static const char *macros[] = { "destruct" }; - static const char *replacement[] = { "dtor" }; - - size_t n; - for ( n = 0; n < WXSIZEOF(macros); n++ ) { - if ( strncmp(funcname + 1, macros[n], strlen(macros[n])) == 0 ) { - // found - break; - } - } - - if ( n == WXSIZEOF(macros) ) { - wxLogWarning("unknown function name '%s' - leaving as is.", - funcname); - } - else { - funcname = replacement[n]; - } - } - - 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 label; -} - -static wxString MakeHelpref(const char *argument) -{ - wxString helpref; - helpref << "\\helpref{" << argument << "}{" << MakeLabel(argument) << '}'; - - 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); - - // undo TeXFilter - static wxRegEx reNonSpecialSpecials("\\\\([#$%&_{}])"), - reAccents("\\\\verb\\|([~^])\\|"); - - reNonSpecialSpecials.ReplaceAll(str, "\\1"); - reAccents.ReplaceAll(str, "\\1"); -} - -static wxString GetAllComments(const spContext& ctx) -{ - wxString comments; - const MCommentListT& commentsList = ctx.GetCommentList(); - for ( MCommentListT::const_iterator i = commentsList.begin(); - i != commentsList.end(); - i++ ) { - wxString comment = (*i)->GetText(); - - // don't take comments like "// ----------" &c - comment.Trim(false); - if ( !comment.empty() && - comment == wxString(comment[0u], comment.length() - 1) + '\n' ) - comments << "\n"; - else - comments << comment; - } - - return comments; -} - -static const char *GetCurrentTimeFormatted(const char *timeFormat) -{ - static char s_timeBuffer[128]; - time_t timeNow; - struct tm *ptmNow; - - time(&timeNow); - ptmNow = localtime(&timeNow); - - strftime(s_timeBuffer, WXSIZEOF(s_timeBuffer), timeFormat, ptmNow); - - return s_timeBuffer; -} - -static const wxString GetVersionString() -{ - wxString version = "$Revision$"; - wxRegEx("^\\$Revision$$").ReplaceFirst(&version, "\\1"); - return version; -} - -/* - $Log$ - Revision 1.45 2007/05/25 20:29:14 VS - compilation fix: can't use wxUniCharRef in switch statement - - 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: */