1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Main program file for HelpGen 
   4 // Author:      Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 
   8 // Copyright:   (c) 1999 VZ 
   9 // Licence:     wxWindows Licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  15     1. wx/string.h confuses C++ parser terribly 
  16     2. C++ parser doesn't know about virtual functions, nor static ones 
  17     3. param checking is not done for vararg functions 
  18     4. type comparison is dumb: it doesn't know that "char *" is the same 
  19        that "char []" nor that "const char *" is the same as "char const *" 
  21    TODO (+ means fixed), see also the change log at the end of the file. 
  23    (i) small fixes in the current version 
  25    +1. Quote special TeX characters like '&' and '_' (=> derive from wxFile) 
  27     3. Document global variables 
  30     6. Include file name/line number in the "diff" messages? 
  31    +7. Support for vararg functions 
  33    (ii) plans for version 2 
  34     1. Use wxTextFile for direct file access to avoid one scan method problems 
  35     2. Use command line parser class for the options 
  36     3. support for overloaded functions in diff mode (search for OVER) 
  38    (iii) plans for version 3 
  39     1. Merging with existing files 
  43 // ============================================================================= 
  45 // ============================================================================= 
  47 // ----------------------------------------------------------------------------- 
  49 // ----------------------------------------------------------------------------- 
  52 #include "wx/wxprec.h" 
  59     #error "HelpGen doesn't build in Unicode mode" 
  63     #include "wx/string.h" 
  65     #include "wx/dynarray.h" 
  73 // C++ parsing classes 
  80 // ----------------------------------------------------------------------------- 
  82 // ----------------------------------------------------------------------------- 
  84 // return the label for the given function name (i.e. argument of \label) 
  85 static wxString 
MakeLabel(const wxChar 
*classname
, const wxChar 
*funcname 
= NULL
); 
  87 // return the whole \helpref{arg}{arg_label} string 
  88 static wxString 
MakeHelpref(const wxChar 
*argument
); 
  90 // [un]quote special TeX characters (in place) 
  91 static void TeXFilter(wxString
* str
); 
  92 static void TeXUnfilter(wxString
* str
); // also trims spaces 
  94 // get all comments associated with this context 
  95 static wxString 
GetAllComments(const spContext
& ctx
); 
  97 // get the string with current time (returns pointer to static buffer) 
  98 // timeFormat is used for the call of strftime(3) 
  99 static const char *GetCurrentTimeFormatted(const char *timeFormat
); 
 101 // get the string containing the program version 
 102 static const wxString 
GetVersionString(); 
 104 // ----------------------------------------------------------------------------- 
 106 // ----------------------------------------------------------------------------- 
 108 // a function documentation entry 
 109 struct FunctionDocEntry
 
 111     FunctionDocEntry(const wxString
& name_
, const wxString
& text_
) 
 112         : name(name_
), text(text_
) { } 
 117     // the function doc text 
 121     static int Compare(FunctionDocEntry 
**pp1
, FunctionDocEntry 
**pp2
) 
 123         // the methods should appear in the following order: ctors, dtor, all 
 124         // the rest in the alphabetical order 
 125         bool isCtor1 
= (*pp1
)->name 
== classname
; 
 126         bool isCtor2 
= (*pp2
)->name 
== classname
; 
 130                 // we don't order the ctors because we don't know how to do it 
 134             // ctor comes before non-ctor 
 139                 // non-ctor must come after ctor 
 143             wxString dtorname 
= wxString(_T("~")) + classname
; 
 145             // there is only one dtor, so the logic here is simpler 
 146             if ( (*pp1
)->name 
== dtorname 
) { 
 149             else if ( (*pp2
)->name 
== dtorname 
) { 
 153             // two normal methods 
 154             return wxStrcmp((*pp1
)->name
, (*pp2
)->name
); 
 158     static wxString classname
; 
 161 wxString 
FunctionDocEntry::classname
; 
 163 WX_DECLARE_OBJARRAY(FunctionDocEntry
, FunctionDocEntries
); 
 165 #include "wx/arrimpl.cpp" 
 167 WX_DEFINE_OBJARRAY(FunctionDocEntries
); 
 169 // add a function which sanitazes the string before writing it to the file and 
 170 // also capable of delaying output and sorting it before really writing it to 
 171 // the file (done from FlushAll()) 
 172 class wxTeXFile 
: public wxFile
 
 177     // write a string to file verbatim (should only be used for the strings 
 178     // inside verbatim environment) 
 179     void WriteVerbatim(const wxString
& s
) 
 184     // write a string quoting TeX specials in it 
 185     void WriteTeX(const wxString
& s
) 
 193     // do write everything to file 
 196         if ( m_text
.empty() ) 
 199         if ( !Write(m_text
) ) { 
 200             wxLogError(_T("Failed to output generated documentation.")); 
 211     wxTeXFile(const wxTeXFile
&); 
 212     wxTeXFile
& operator=(const wxTeXFile
&); 
 217 // helper class which manages the classes and function names to ignore for 
 218 // the documentation purposes (used by both HelpGenVisitor and DocManager) 
 219 class IgnoreNamesHandler
 
 222     IgnoreNamesHandler() : m_ignore(CompareIgnoreListEntries
) { } 
 223     ~IgnoreNamesHandler() { WX_CLEAR_ARRAY(m_ignore
); } 
 225     // load file with classes/functions to ignore (add them to the names we 
 227     bool AddNamesFromFile(const wxString
& filename
); 
 229     // return true if we ignore this function 
 230     bool IgnoreMethod(const wxString
& classname
, 
 231                       const wxString
& funcname
) const 
 233         if ( IgnoreClass(classname
) ) 
 236         IgnoreListEntry 
ignore(classname
, funcname
); 
 238         return m_ignore
.Index(&ignore
) != wxNOT_FOUND
; 
 241     // return true if we ignore this class entirely 
 242     bool IgnoreClass(const wxString
& classname
) const 
 244         IgnoreListEntry 
ignore(classname
, wxEmptyString
); 
 246         return m_ignore
.Index(&ignore
) != wxNOT_FOUND
; 
 250     struct IgnoreListEntry
 
 252         IgnoreListEntry(const wxString
& classname
, 
 253                         const wxString
& funcname
) 
 254             : m_classname(classname
), m_funcname(funcname
) 
 258         wxString m_classname
; 
 259         wxString m_funcname
;    // if empty, ignore class entirely 
 262     static int CompareIgnoreListEntries(IgnoreListEntry 
*first
, 
 263                                         IgnoreListEntry 
*second
); 
 265     // for efficiency, let's sort it 
 266 public: // FIXME: macro requires it 
 267     WX_DEFINE_SORTED_ARRAY(IgnoreListEntry 
*, ArrayNamesToIgnore
); 
 270     ArrayNamesToIgnore m_ignore
; 
 273     IgnoreNamesHandler(const IgnoreNamesHandler
&); 
 274     IgnoreNamesHandler
& operator=(const IgnoreNamesHandler
&); 
 277 // visitor implementation which writes all collected data to a .tex file 
 278 class HelpGenVisitor 
: public spVisitor
 
 282     HelpGenVisitor(const wxString
& directoryOut
, bool overwrite
); 
 284     virtual void VisitFile( spFile
& fl 
); 
 285     virtual void VisitClass( spClass
& cl 
); 
 286     virtual void VisitEnumeration( spEnumeration
& en 
); 
 287     virtual void VisitTypeDef( spTypeDef
& td 
); 
 288     virtual void VisitPreprocessorLine( spPreprocessorLine
& pd 
); 
 289     virtual void VisitAttribute( spAttribute
& attr 
); 
 290     virtual void VisitOperation( spOperation
& op 
); 
 291     virtual void VisitParameter( spParameter
& param 
); 
 295     // get our `ignore' object 
 296     IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; } 
 298     // shut up g++ warning (ain't it stupid?) 
 299     virtual ~HelpGenVisitor() { } 
 302     // (re)initialize the state 
 305     // insert documentation for enums/typedefs coming immediately before the 
 306     // class declaration into the class documentation 
 307     void InsertTypedefDocs(); 
 308     void InsertEnumDocs(); 
 310     // write the headers for corresponding sections (only once) 
 311     void InsertDataStructuresHeader(); 
 312     void InsertMethodsHeader(); 
 314     // terminate the function documentation if it was started 
 315     void CloseFunction(); 
 317     // write out all function docs when there are no more left in this class 
 318     // after sorting them in alphabetical order 
 321     wxString  m_directoryOut
,   // directory for the output 
 322               m_fileHeader
;     // name of the .h file we parse 
 323     bool      m_overwrite
;      // overwrite existing files? 
 324     wxTeXFile m_file
;           // file we're writing to now 
 327     bool m_inClass
,         // true after file successfully opened 
 328          m_inTypesSection
,  // enums & typedefs go there 
 329          m_inMethodSection
, // functions go here 
 330          m_isFirstParam
;    // first parameter of current function? 
 332     // non empty while parsing a class 
 333     wxString m_classname
; 
 335     // these are only non-empty while parsing a method: 
 336     wxString m_funcName
,    // the function name 
 337              m_textFunc
;    // the function doc text 
 339     // the array containing the documentation entries for the functions in the 
 340     // class currently being parsed 
 341     FunctionDocEntries m_arrayFuncDocs
; 
 343     // holders for "saved" documentation 
 344     wxString m_textStoredTypedefs
, 
 345              m_textStoredFunctionComment
; 
 347     // for enums we have to use an array as we can't intermix the normal text 
 348     // and the text inside verbatim environment 
 349     wxArrayString m_storedEnums
, 
 352     // headers included by this file 
 353     wxArrayString m_headers
; 
 355     // ignore handler: tells us which classes to ignore for doc generation 
 357     IgnoreNamesHandler m_ignoreNames
; 
 360     HelpGenVisitor(const HelpGenVisitor
&); 
 361     HelpGenVisitor
& operator=(const HelpGenVisitor
&); 
 364 // documentation manager - a class which parses TeX files and remembers the 
 365 // functions documented in them and can later compare them with all functions 
 366 // found under ctxTop by C++ parser 
 370     DocManager(bool checkParamNames
); 
 373     // returns false on failure 
 374     bool ParseTeXFile(const wxString
& filename
); 
 376     // returns false if there were any differences 
 377     bool DumpDifferences(spContext 
*ctxTop
) const; 
 379     // get our `ignore' object 
 380     IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; } 
 386     // returns the length of 'match' if the string 'str' starts with it or 0 
 388     static size_t TryMatch(const wxChar 
*str
, const wxChar 
*match
); 
 390     // skip spaces: returns pointer to first non space character (also 
 391     // updates the value of m_line) 
 392     const char *SkipSpaces(const char *p
) 
 394         while ( isspace(*p
) ) { 
 402     // skips characters until the next 'c' in '*pp' unless it ends before in 
 403     // which case false is returned and pp points to '\0', otherwise true is 
 404     // returned and pp points to 'c' 
 405     bool SkipUntil(const char **pp
, char c
); 
 407     // the same as SkipUntil() but only spaces are skipped: on first non space 
 408     // character different from 'c' the function stops and returns false 
 409     bool SkipSpaceUntil(const char **pp
, char c
); 
 411     // extract the string between {} and modify '*pp' to point at the 
 412     // character immediately after the closing '}'. The returned string is empty 
 414     wxString 
ExtractStringBetweenBraces(const char **pp
); 
 416     // the current file and line while we're in ParseTeXFile (for error 
 421     // functions and classes to ignore during diff 
 422     // ------------------------------------------- 
 424     IgnoreNamesHandler m_ignoreNames
; 
 426     // information about all functions documented in the TeX file(s) 
 427     // ------------------------------------------------------------- 
 429 public: // Note: Sun C++ 5.5 requires TypeInfo and ParamInfo to be public 
 431     // info about a type: for now stored as text string, but must be parsed 
 432     // further later (to know that "char *" == "char []" - TODO) 
 436         TypeInfo(const wxString
& type
) : m_type(type
) { } 
 438         bool operator==(const wxString
& type
) const { return m_type 
== type
; } 
 439         bool operator!=(const wxString
& type
) const { return m_type 
!= type
; } 
 441         const wxString
& GetName() const { return m_type
; } 
 447     friend class ParamInfo
; // for access to TypeInfo 
 449     // info abotu a function parameter 
 453         ParamInfo(const wxString
& type
, 
 454                   const wxString
& name
, 
 455                   const wxString
& value
) 
 456             : m_type(type
), m_name(name
), m_value(value
) 
 460         const TypeInfo
& GetType() const { return m_type
; } 
 461         const wxString
& GetName() const { return m_name
; } 
 462         const wxString
& GetDefValue() const { return m_value
; } 
 465         TypeInfo m_type
;      // type of parameter 
 466         wxString m_name
;      // name 
 467         wxString m_value
;     // default value 
 470 public: // FIXME: macro requires it 
 471     WX_DEFINE_ARRAY_PTR(ParamInfo 
*, ArrayParamInfo
); 
 473     // info about a function 
 486         MethodInfo(const wxString
& type
, 
 487                    const wxString
& name
, 
 488                    const ArrayParamInfo
& params
) 
 489             : m_typeRet(type
), m_name(name
), m_params(params
) 
 494         void SetFlag(MethodFlags flag
) { m_flags 
|= flag
; } 
 496         const TypeInfo
& GetType() const { return m_typeRet
; } 
 497         const wxString
& GetName() const { return m_name
; } 
 498         const ParamInfo
& GetParam(size_t n
) const { return *(m_params
[n
]); } 
 499         size_t GetParamCount() const { return m_params
.GetCount(); } 
 501         bool HasFlag(MethodFlags flag
) const { return (m_flags 
& flag
) != 0; } 
 503         ~MethodInfo() { WX_CLEAR_ARRAY(m_params
); } 
 506         TypeInfo m_typeRet
;     // return type 
 508         int      m_flags
;       // bit mask of the value from the enum above 
 510         ArrayParamInfo m_params
; 
 513     WX_DEFINE_ARRAY_PTR(MethodInfo 
*, ArrayMethodInfo
); 
 514     WX_DEFINE_ARRAY_PTR(ArrayMethodInfo 
*, ArrayMethodInfos
); 
 517     // first array contains the names of all classes we found, the second has a 
 518     // pointer to the array of methods of the given class at the same index as 
 519     // the class name appears in m_classes 
 520     wxArrayString    m_classes
; 
 521     ArrayMethodInfos m_methods
; 
 523     // are we checking parameter names? 
 524     bool m_checkParamNames
; 
 527     DocManager(const DocManager
&); 
 528     DocManager
& operator=(const DocManager
&); 
 531 // ============================================================================= 
 533 // ============================================================================= 
 535 static char **g_argv 
= NULL
; 
 537 // this function never returns 
 540     wxString prog 
= g_argv
[0]; 
 541     wxString basename 
= prog
.AfterLast('/'); 
 544         basename 
= prog
.AfterLast('\\'); 
 550 "usage: %s [global options] <mode> [mode options] <files...>\n" 
 552 "   where global options are:\n" 
 555 "       -H          give this usage message\n" 
 556 "       -V          print the version info\n" 
 557 "       -i file     file with classes/function to ignore\n" 
 559 "   where mode is one of: dump, diff\n" 
 561 "   dump means generate .tex files for TeX2RTF converter from specified\n" 
 562 "   headers files, mode options are:\n" 
 563 "       -f          overwrite existing files\n" 
 564 "       -o outdir   directory for generated files\n" 
 566 "   diff means compare the set of methods documented .tex file with the\n" 
 567 "   methods declared in the header:\n" 
 568 "           %s diff <file.h> <files.tex...>.\n" 
 569 "   mode specific options are:\n" 
 570 "       -p          do check parameter names (not done by default)\n" 
 571 "\n", basename
.c_str(), basename
.c_str()); 
 576 int main(int argc
, char **argv
) 
 580     wxInitializer initializer
; 
 583         fprintf(stderr
, "Failed to initialize the wxWidgets library, aborting."); 
 599     wxArrayString filesH
, filesTeX
; 
 600     wxString directoryOut
,      // directory for 'dmup' output 
 601              ignoreFile
;        // file with classes/functions to ignore 
 602     bool overwrite 
= false,     // overwrite existing files during 'dump'? 
 603          paramNames 
= false;    // check param names during 'diff'? 
 605     for ( int current 
= 1; current 
< argc 
; current
++ ) { 
 606         // all options have one letter 
 607         if ( argv
[current
][0] == '-' ) { 
 608             if ( argv
[current
][2] == '\0' ) { 
 609                 switch ( argv
[current
][1] ) { 
 612                         wxLog::GetActiveTarget()->SetVerbose(); 
 617                         wxLog::GetActiveTarget()->SetVerbose(false); 
 627                         wxLogMessage("HelpGen version %s\n" 
 628                                      "(c) 1999-2001 Vadim Zeitlin\n", 
 629                                      GetVersionString().c_str()); 
 634                         if ( current 
>= argc 
) { 
 635                             wxLogError("-i option requires an argument."); 
 640                         ignoreFile 
= argv
[current
]; 
 644                         if ( mode 
!= Mode_Diff 
) { 
 645                             wxLogError("-p is only valid with diff."); 
 654                         if ( mode 
!= Mode_Dump 
) { 
 655                             wxLogError("-f is only valid with dump."); 
 664                         if ( mode 
!= Mode_Dump 
) { 
 665                             wxLogError("-o is only valid with dump."); 
 671                         if ( current 
>= argc 
) { 
 672                             wxLogError("-o option requires an argument."); 
 677                         directoryOut 
= argv
[current
]; 
 678                         if ( !directoryOut
.empty() ) { 
 679                             // terminate with a '/' if it doesn't have it 
 680                             switch ( directoryOut
.Last() ) { 
 691                         //else: it's empty, do nothing 
 696                         wxLogError("unknown option '%s'", argv
[current
]); 
 701                 wxLogError("only one letter options are allowed, not '%s'.", 
 705             // only get here after a break from switch or from else branch of if 
 710             if ( mode 
== Mode_None 
) { 
 711                 if ( strcmp(argv
[current
], "diff") == 0 ) 
 713                 else if ( strcmp(argv
[current
], "dump") == 0 ) 
 716                     wxLogError("unknown mode '%s'.", argv
[current
]); 
 722                 if ( mode 
== Mode_Dump 
|| filesH
.IsEmpty() ) { 
 723                     filesH
.Add(argv
[current
]); 
 726                     // 2nd files and further are TeX files in diff mode 
 727                     wxASSERT( mode 
== Mode_Diff 
); 
 729                     filesTeX
.Add(argv
[current
]); 
 735     // create a parser object and a visitor derivation 
 736     CJSourceParser parser
; 
 737     HelpGenVisitor 
visitor(directoryOut
, overwrite
); 
 738     if ( !ignoreFile
.empty() && mode 
== Mode_Dump 
) 
 739         visitor
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
); 
 741     spContext 
*ctxTop 
= NULL
; 
 743     // parse all header files 
 744     size_t nFiles 
= filesH
.GetCount(); 
 745     for ( size_t n 
= 0; n 
< nFiles
; n
++ ) { 
 746         wxString header 
= filesH
[n
]; 
 747         ctxTop 
= parser
.ParseFile(header
); 
 749             wxLogWarning("Header file '%s' couldn't be processed.", 
 752         else if ( mode 
== Mode_Dump 
) { 
 753             ((spFile 
*)ctxTop
)->mFileName 
= header
; 
 754             visitor
.VisitAll(*ctxTop
); 
 760             ctxTop
->Dump(wxEmptyString
); 
 761 #endif // __WXDEBUG__ 
 764     // parse all TeX files 
 765     if ( mode 
== Mode_Diff 
) { 
 767             wxLogError("Can't complete diff."); 
 773         DocManager 
docman(paramNames
); 
 775         size_t nFiles 
= filesTeX
.GetCount(); 
 776         for ( size_t n 
= 0; n 
< nFiles
; n
++ ) { 
 777             wxString file 
= filesTeX
[n
]; 
 778             if ( !docman
.ParseTeXFile(file
) ) { 
 779                 wxLogWarning("TeX file '%s' couldn't be processed.", 
 784         if ( !ignoreFile
.empty() ) 
 785             docman
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
); 
 787         docman
.DumpDifferences(ctxTop
); 
 793 // ----------------------------------------------------------------------------- 
 794 // HelpGenVisitor implementation 
 795 // ----------------------------------------------------------------------------- 
 797 HelpGenVisitor::HelpGenVisitor(const wxString
& directoryOut
, 
 799               : m_directoryOut(directoryOut
) 
 801     m_overwrite 
= overwrite
; 
 806 void HelpGenVisitor::Reset() 
 810     m_inMethodSection 
= false; 
 815     m_textStoredTypedefs 
= 
 816     m_textStoredFunctionComment 
= wxEmptyString
; 
 818     m_arrayFuncDocs
.Empty(); 
 820     m_storedEnums
.Empty(); 
 821     m_storedEnumsVerb
.Empty(); 
 825 void HelpGenVisitor::InsertTypedefDocs() 
 827     m_file
.WriteTeX(m_textStoredTypedefs
); 
 828     m_textStoredTypedefs
.Empty(); 
 831 void HelpGenVisitor::InsertEnumDocs() 
 833     size_t count 
= m_storedEnums
.GetCount(); 
 834     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 836         m_file
.WriteTeX(m_storedEnums
[n
]); 
 837         m_file
.WriteVerbatim(m_storedEnumsVerb
[n
] + '\n'); 
 840     m_storedEnums
.Empty(); 
 841     m_storedEnumsVerb
.Empty(); 
 844 void HelpGenVisitor::InsertDataStructuresHeader() 
 846     if ( !m_inTypesSection 
) { 
 847         m_inTypesSection 
= true; 
 849         m_file
.WriteVerbatim("\\wxheading{Data structures}\n\n"); 
 853 void HelpGenVisitor::InsertMethodsHeader() 
 855     if ( !m_inMethodSection 
) { 
 856         m_inMethodSection 
= true; 
 858         m_file
.WriteVerbatim( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n"); 
 862 void HelpGenVisitor::CloseFunction() 
 864     if ( !m_funcName
.empty() ) { 
 865         if ( m_isFirstParam 
) { 
 867             m_textFunc 
<< "\\void"; 
 870         m_textFunc 
<< "}\n\n"; 
 872         if ( !m_textStoredFunctionComment
.empty() ) { 
 873             m_textFunc 
<< m_textStoredFunctionComment 
<< '\n'; 
 876         m_arrayFuncDocs
.Add(new FunctionDocEntry(m_funcName
, m_textFunc
)); 
 882 void HelpGenVisitor::CloseClass() 
 888         size_t count 
= m_arrayFuncDocs
.GetCount(); 
 892             FunctionDocEntry::classname 
= m_classname
; 
 894             m_arrayFuncDocs
.Sort(FunctionDocEntry::Compare
); 
 896             // Now examine each first line and if it's been seen, cut it 
 897             // off (it's a duplicate \membersection) 
 898             wxHashTable 
membersections(wxKEY_STRING
); 
 900             for ( n 
= 0; n 
< count
; n
++ ) 
 902                 wxString 
section(m_arrayFuncDocs
[n
].text
); 
 904                 // Strip leading whitespace 
 905                 int pos 
= section
.Find("\\membersection"); 
 908                     section 
= section
.Mid(pos
); 
 911                 wxString 
ms(section
.BeforeFirst(wxT('\n'))); 
 912                 if (membersections
.Get(ms
)) 
 914                     m_arrayFuncDocs
[n
].text 
= section
.AfterFirst(wxT('\n')); 
 918                     membersections
.Put(ms
.c_str(), & membersections
); 
 922             for ( n 
= 0; n 
< count
; n
++ ) { 
 923                 m_file
.WriteTeX(m_arrayFuncDocs
[n
].text
); 
 926             m_arrayFuncDocs
.Empty(); 
 935 void HelpGenVisitor::EndVisit() 
 941     m_fileHeader
.Empty(); 
 944     if (m_file
.IsOpened()) 
 950     wxLogVerbose("%s: finished generating for the current file.", 
 951                  GetCurrentTimeFormatted("%H:%M:%S")); 
 954 void HelpGenVisitor::VisitFile( spFile
& file 
) 
 956     m_fileHeader 
= file
.mFileName
; 
 957     wxLogVerbose("%s: started generating docs for classes from file '%s'...", 
 958                  GetCurrentTimeFormatted("%H:%M:%S"), m_fileHeader
.c_str()); 
 961 void HelpGenVisitor::VisitClass( spClass
& cl 
) 
 965     if (m_file
.IsOpened()) 
 971     wxString name 
= cl
.GetName(); 
 973     if ( m_ignoreNames
.IgnoreClass(name
) ) { 
 974         wxLogVerbose("Skipping ignored class '%s'.", name
.c_str()); 
 979     // the file name is built from the class name by removing the leading "wx" 
 980     // if any and converting it to the lower case 
 982     if ( name(0, 2) == "wx" ) { 
 983         filename 
<< name
.c_str() + 2; 
 989     filename
.MakeLower(); 
 991     filename
.Prepend(m_directoryOut
); 
 993     if ( !m_overwrite 
&& wxFile::Exists(filename
) ) { 
 994         wxLogError("Won't overwrite existing file '%s' - please use '-f'.", 
1000     m_inClass 
= m_file
.Open(filename
, wxFile::write
); 
1002         wxLogError("Can't generate documentation for the class '%s'.", 
1009     m_inTypesSection 
= false; 
1011     wxLogInfo("Created new file '%s' for class '%s'.", 
1012               filename
.c_str(), name
.c_str()); 
1014     // write out the header 
1016     header
.Printf("%%\n" 
1017                   "%% automatically generated by HelpGen %s from\n" 
1022                   "\\section{\\class{%s}}\\label{%s}\n\n", 
1023                   GetVersionString().c_str(), 
1024                   m_fileHeader
.c_str(), 
1025                   GetCurrentTimeFormatted("%d/%b/%y %H:%M:%S"), 
1027                   wxString(name
).MakeLower().c_str()); 
1029     m_file
.WriteVerbatim(header
); 
1031     // the entire text we're writing to file 
1034     // if the header includes other headers they must be related to it... try to 
1035     // automatically generate the "See also" clause 
1036     if ( !m_headers
.IsEmpty() ) { 
1037         // correspondence between wxWidgets headers and class names 
1038         static const char *headers
[] = { 
1047         // NULL here means not to insert anything in "See also" for the 
1048         // corresponding header 
1049         static const char *classes
[] = { 
1058         wxASSERT_MSG( WXSIZEOF(headers
) == WXSIZEOF(classes
), 
1059                       "arrays must be in sync!" ); 
1061         wxArrayInt interestingClasses
; 
1063         size_t count 
= m_headers
.Count(), index
; 
1064         for ( size_t n 
= 0; n 
< count
; n
++ ) { 
1065             wxString baseHeaderName 
= m_headers
[n
].Before('.'); 
1066             if ( baseHeaderName(0, 3) != "wx/" ) 
1069             baseHeaderName
.erase(0, 3); 
1070             for ( index 
= 0; index 
< WXSIZEOF(headers
); index
++ ) { 
1071                 if ( Stricmp(baseHeaderName
, headers
[index
]) == 0 ) 
1075             if ( (index 
< WXSIZEOF(headers
)) && classes
[index
] ) { 
1076                 // interesting header 
1077                 interestingClasses
.Add(index
); 
1081         if ( !interestingClasses
.IsEmpty() ) { 
1082             // do generate "See also" clause 
1083             totalText 
<< "\\wxheading{See also:}\n\n"; 
1085             count 
= interestingClasses
.Count(); 
1086             for ( index 
= 0; index 
< count
; index
++ ) { 
1090                 totalText 
<< MakeHelpref(classes
[interestingClasses
[index
]]); 
1093             totalText 
<< "\n\n"; 
1097     // the comment before the class generally explains what is it for so put it 
1098     // in place of the class description 
1099     if ( cl
.HasComments() ) { 
1100         wxString comment 
= GetAllComments(cl
); 
1102         totalText 
<< '\n' << comment 
<< '\n'; 
1105     // derived from section 
1106     wxString derived 
= "\\wxheading{Derived from}\n\n"; 
1108     const StrListT
& baseClasses 
= cl
.m_SuperClassNames
; 
1109     if ( baseClasses
.size() == 0 ) { 
1110         derived 
<< "No base class"; 
1114         for ( StrListT::const_iterator i 
= baseClasses
.begin(); 
1115               i 
!= baseClasses
.end(); 
1118                 // separate from the previous one 
1119                 derived 
<< "\\\\\n"; 
1125             wxString baseclass 
= *i
; 
1126             derived 
<< "\\helpref{" << baseclass 
<< "}"; 
1127             derived 
<< "{" << baseclass
.MakeLower()  << "}"; 
1130     totalText 
<< derived 
<< "\n\n"; 
1132     // include file section 
1133     wxString includeFile 
= "\\wxheading{Include files}\n\n"; 
1134     includeFile 
<< "<" << m_fileHeader 
<< ">"; 
1136     totalText 
<< includeFile 
<< "\n\n"; 
1138     // write all this to file 
1139     m_file
.WriteTeX(totalText
); 
1141     // if there were any enums/typedefs before, insert their documentation now 
1142     InsertDataStructuresHeader(); 
1143     InsertTypedefDocs(); 
1149 void HelpGenVisitor::VisitEnumeration( spEnumeration
& en 
) 
1153     if ( m_inMethodSection 
) { 
1154         // FIXME that's a bug, but tell the user aboit it nevertheless... we 
1155         // should be smart enough to process even the enums which come after the 
1157         wxLogWarning("enum '%s' ignored, please put it before the class " 
1158                      "methods.", en
.GetName().c_str()); 
1162     // simply copy the enum text in the docs 
1163     wxString enumeration 
= GetAllComments(en
), 
1166     enumerationVerb 
<< _T("\\begin{verbatim}\n") 
1168                     << _T("\n\\end{verbatim}\n"); 
1170     // remember for later use if we're not inside a class yet 
1172         m_storedEnums
.Add(enumeration
); 
1173         m_storedEnumsVerb
.Add(enumerationVerb
); 
1176         // write the header for this section if not done yet 
1177         InsertDataStructuresHeader(); 
1179         m_file
.WriteTeX(enumeration
); 
1180         m_file
.WriteVerbatim(enumerationVerb
); 
1181         m_file
.WriteVerbatim('\n'); 
1185 void HelpGenVisitor::VisitTypeDef( spTypeDef
& td 
) 
1189     if ( m_inMethodSection 
) { 
1190         // FIXME that's a bug, but tell the user aboit it nevertheless... 
1191         wxLogWarning("typedef '%s' ignored, please put it before the class " 
1192                      "methods.", td
.GetName().c_str()); 
1196     wxString typedefdoc
; 
1197     typedefdoc 
<< _T("{\\small \\begin{verbatim}\n") 
1198                << _T("typedef ") << td
.m_OriginalType 
<< _T(' ') << td
.GetName() 
1199                << _T("\n\\end{verbatim}}\n") 
1200                << GetAllComments(td
); 
1202     // remember for later use if we're not inside a class yet 
1204         if ( !m_textStoredTypedefs
.empty() ) { 
1205             m_textStoredTypedefs 
<< '\n'; 
1208         m_textStoredTypedefs 
<< typedefdoc
; 
1211         // write the header for this section if not done yet 
1212         InsertDataStructuresHeader(); 
1215         m_file
.WriteTeX(typedefdoc
); 
1219 void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine
& pd 
) 
1221     switch ( pd
.GetStatementType() ) { 
1222         case SP_PREP_DEF_INCLUDE_FILE
: 
1223             m_headers
.Add(pd
.CPP_GetIncludedFileNeme()); 
1226         case SP_PREP_DEF_DEFINE_SYMBOL
: 
1227             // TODO decide if it's a constant and document it if it is 
1232 void HelpGenVisitor::VisitAttribute( spAttribute
& attr 
) 
1236     // only document the public member variables 
1237     if ( !m_inClass 
|| !attr
.IsPublic() ) 
1240     wxLogWarning("Ignoring member variable '%s'.", attr
.GetName().c_str()); 
1243 void HelpGenVisitor::VisitOperation( spOperation
& op 
) 
1248         // we don't generate docs right now - either we ignore this class 
1249         // entirely or we couldn't open the file 
1253     if ( !op
.IsInClass() ) { 
1254         // TODO document global functions 
1255         wxLogWarning("skipped global function '%s'.", op
.GetName().c_str()); 
1260     if ( op
.mVisibility 
== SP_VIS_PRIVATE 
) { 
1261         // FIXME should we document protected functions? 
1265     m_classname 
= op
.GetClass().GetName(); 
1266     wxString funcname 
= op
.GetName(); 
1268     if ( m_ignoreNames
.IgnoreMethod(m_classname
, funcname
) ) { 
1269         wxLogVerbose("Skipping ignored '%s::%s'.", 
1270                      m_classname
.c_str(), funcname
.c_str()); 
1275     InsertMethodsHeader(); 
1278     m_funcName 
= funcname
; 
1279     m_isFirstParam 
= true; 
1281     m_textStoredFunctionComment 
= GetAllComments(op
); 
1283     // start function documentation 
1286     // check for the special case of dtor 
1288     if ( (funcname
[0u] == '~') && (m_classname 
== funcname
.c_str() + 1) ) { 
1289         dtor
.Printf("\\destruct{%s}", m_classname
.c_str()); 
1293     m_textFunc
.Printf("\n" 
1294         "\\membersection{%s::%s}\\label{%s}\n", 
1295         m_classname
.c_str(), funcname
.c_str(), 
1296         MakeLabel(m_classname
, funcname
).c_str()); 
1300                       "\\%sfunc{%s%s}{%s}{", 
1301                       op
.mIsConstant 
? "const" : "", 
1302                       op
.mIsVirtual 
? "virtual " : "", 
1303                       op
.m_RetType
.c_str(), 
1308 void HelpGenVisitor::VisitParameter( spParameter
& param 
) 
1310     if ( m_funcName
.empty() ) 
1313     if ( m_isFirstParam 
) { 
1314         m_isFirstParam 
= false; 
1320     m_textFunc 
<< "\\param{" << param
.m_Type 
<< " }{" << param
.GetName(); 
1321     wxString defvalue 
= param
.m_InitVal
; 
1322     if ( !defvalue
.empty() ) { 
1323         m_textFunc 
<< " = " << defvalue
; 
1329 // --------------------------------------------------------------------------- 
1331 // --------------------------------------------------------------------------- 
1333 DocManager::DocManager(bool checkParamNames
) 
1335     m_checkParamNames 
= checkParamNames
; 
1338 size_t DocManager::TryMatch(const char *str
, const char *match
) 
1340     size_t lenMatch 
= 0; 
1341     while ( str
[lenMatch
] == match
[lenMatch
] ) { 
1344         if ( match
[lenMatch
] == '\0' ) 
1351 bool DocManager::SkipUntil(const char **pp
, char c
) 
1353     const char *p 
= *pp
; 
1369 bool DocManager::SkipSpaceUntil(const char **pp
, char c
) 
1371     const char *p 
= *pp
; 
1373         if ( !isspace(*p
) || *p 
== '\0' ) 
1387 wxString 
DocManager::ExtractStringBetweenBraces(const char **pp
) 
1391     if ( !SkipSpaceUntil(pp
, '{') ) { 
1392         wxLogWarning("file %s(%d): '{' expected after '\\param'", 
1393                      m_filename
.c_str(), (int)m_line
); 
1397         const char *startParam 
= ++*pp
; // skip '{' 
1399         if ( !SkipUntil(pp
, '}') ) { 
1400             wxLogWarning("file %s(%d): '}' expected after '\\param'", 
1401                          m_filename
.c_str(), (int)m_line
); 
1404             result 
= wxString(startParam
, (*pp
)++ - startParam
); 
1411 bool DocManager::ParseTeXFile(const wxString
& filename
) 
1413     m_filename 
= filename
; 
1415     wxFile 
file(m_filename
, wxFile::read
); 
1416     if ( !file
.IsOpened() ) 
1419     off_t len 
= file
.Length(); 
1420     if ( len 
== wxInvalidOffset 
) 
1423     char *buf 
= new char[len 
+ 1]; 
1426     if ( file
.Read(buf
, len
) == wxInvalidOffset 
) { 
1432     // reinit everything 
1435     wxLogVerbose("%s: starting to parse doc file '%s'.", 
1436                  GetCurrentTimeFormatted("%H:%M:%S"), m_filename
.c_str()); 
1438     // the name of the class from the last "\membersection" command: we assume 
1439     // that the following "\func" or "\constfunc" always documents a method of 
1440     // this class (and it should always be like that in wxWidgets documentation) 
1443     for ( const char *current 
= buf
; current 
- buf 
< len
; current
++ ) { 
1444         // FIXME parsing is awfully inefficient 
1446         if ( *current 
== '%' ) { 
1447             // comment, skip until the end of line 
1449             SkipUntil(¤t
, '\n'); 
1454         // all the command we're interested in start with '\\' 
1455         while ( *current 
!= '\\' && *current 
!= '\0' ) { 
1456             if ( *current
++ == '\n' ) 
1460         if ( *current 
== '\0' ) { 
1461             // no more TeX commands left 
1465         current
++; // skip '\\' 
1473         } foundCommand 
= Nothing
; 
1475         size_t lenMatch 
= TryMatch(current
, "func"); 
1477             foundCommand 
= Func
; 
1480             lenMatch 
= TryMatch(current
, "constfunc"); 
1482                 foundCommand 
= ConstFunc
; 
1484                 lenMatch 
= TryMatch(current
, "membersection"); 
1487                     foundCommand 
= MemberSect
; 
1491         if ( foundCommand 
== Nothing 
) 
1494         current 
+= lenMatch
; 
1496         if ( !SkipSpaceUntil(¤t
, '{') ) { 
1497             wxLogWarning("file %s(%d): '{' expected after \\func, " 
1498                          "\\constfunc or \\membersection.", 
1499                          m_filename
.c_str(), (int)m_line
); 
1506         if ( foundCommand 
== MemberSect 
) { 
1507             // what follows has the form <classname>::<funcname> 
1508             const char *startClass 
= current
; 
1509             if ( !SkipUntil(¤t
, ':') || *(current 
+ 1) != ':' ) { 
1510                 wxLogWarning("file %s(%d): '::' expected after " 
1511                              "\\membersection.", m_filename
.c_str(), (int)m_line
); 
1514                 classname 
= wxString(startClass
, current 
- startClass
); 
1515                 TeXUnfilter(&classname
); 
1521         // extract the return type 
1522         const char *startRetType 
= current
; 
1524         if ( !SkipUntil(¤t
, '}') ) { 
1525             wxLogWarning("file %s(%d): '}' expected after return type", 
1526                          m_filename
.c_str(), (int)m_line
); 
1531         wxString returnType 
= wxString(startRetType
, current 
- startRetType
); 
1532         TeXUnfilter(&returnType
); 
1535         if ( !SkipSpaceUntil(¤t
, '{') ) { 
1536             wxLogWarning("file %s(%d): '{' expected after return type", 
1537                          m_filename
.c_str(), (int)m_line
); 
1543         const char *funcEnd 
= current
; 
1544         if ( !SkipUntil(&funcEnd
, '}') ) { 
1545             wxLogWarning("file %s(%d): '}' expected after function name", 
1546                          m_filename
.c_str(), (int)m_line
); 
1551         wxString funcName 
= wxString(current
, funcEnd 
- current
); 
1552         current 
= funcEnd 
+ 1; 
1554         // trim spaces from both sides 
1555         funcName
.Trim(false); 
1556         funcName
.Trim(true); 
1558         // special cases: '$...$' may be used for LaTeX inline math, remove the 
1560         if ( funcName
.Find('$') != wxNOT_FOUND 
) { 
1562             for ( const char *p 
= funcName
.c_str(); *p 
!= '\0'; p
++ ) { 
1563                 if ( *p 
!= '$' && !isspace(*p
) ) 
1570         // \destruct{foo} is really ~foo 
1571         if ( funcName
[0u] == '\\' ) { 
1572             size_t len 
= strlen("\\destruct{"); 
1573             if ( funcName(0, len
) != "\\destruct{" ) { 
1574                 wxLogWarning("file %s(%d): \\destruct expected", 
1575                              m_filename
.c_str(), (int)m_line
); 
1580             funcName
.erase(0, len
); 
1581             funcName
.Prepend('~'); 
1583             if ( !SkipSpaceUntil(¤t
, '}') ) { 
1584                 wxLogWarning("file %s(%d): '}' expected after destructor", 
1585                              m_filename
.c_str(), (int)m_line
); 
1590             funcEnd
++;  // there is an extra '}' to count 
1593         TeXUnfilter(&funcName
); 
1596         current 
= funcEnd 
+ 1; // skip '}' 
1597         if ( !SkipSpaceUntil(¤t
, '{') || 
1598              (current
++, !SkipSpaceUntil(¤t
, '\\')) ) { 
1599             wxLogWarning("file %s(%d): '\\param' or '\\void' expected", 
1600                          m_filename
.c_str(), (int)m_line
); 
1605         wxArrayString paramNames
, paramTypes
, paramValues
; 
1607         bool isVararg 
= false; 
1609         current
++; // skip '\\' 
1610         lenMatch 
= TryMatch(current
, "void"); 
1612             lenMatch 
= TryMatch(current
, "param"); 
1613             while ( lenMatch 
&& (current 
- buf 
< len
) ) { 
1614                 current 
+= lenMatch
; 
1616                 // now come {paramtype}{paramname} 
1617                 wxString paramType 
= ExtractStringBetweenBraces(¤t
); 
1618                 if ( !paramType
.empty() ) { 
1619                     wxString paramText 
= ExtractStringBetweenBraces(¤t
); 
1620                     if ( !paramText
.empty() ) { 
1621                         // the param declaration may contain default value 
1622                         wxString paramName 
= paramText
.BeforeFirst('='), 
1623                                  paramValue 
= paramText
.AfterFirst('='); 
1625                         // sanitize all strings 
1626                         TeXUnfilter(¶mValue
); 
1627                         TeXUnfilter(¶mName
); 
1628                         TeXUnfilter(¶mType
); 
1630                         paramValues
.Add(paramValue
); 
1631                         paramNames
.Add(paramName
); 
1632                         paramTypes
.Add(paramType
); 
1637                     wxString paramText 
= ExtractStringBetweenBraces(¤t
); 
1638                     if ( paramText 
== "..." ) { 
1642                         wxLogWarning("Parameters of '%s::%s' are in " 
1644                                      classname
.c_str(), funcName
.c_str()); 
1649                 current 
= SkipSpaces(current
); 
1650                 if ( *current 
== ',' || *current 
== '}' ) { 
1651                     current 
= SkipSpaces(++current
); 
1653                     lenMatch 
= TryMatch(current
, "\\param"); 
1656                     wxLogWarning("file %s(%d): ',' or '}' expected after " 
1657                                  "'\\param'", m_filename
.c_str(), (int)m_line
); 
1663             // if we got here there was no '\\void', so must have some params 
1664             if ( paramNames
.IsEmpty() ) { 
1665                 wxLogWarning("file %s(%d): '\\param' or '\\void' expected", 
1666                         m_filename
.c_str(), (int)m_line
); 
1672         // verbose diagnostic output 
1674         size_t param
, paramCount 
= paramNames
.GetCount(); 
1675         for ( param 
= 0; param 
< paramCount
; param
++ ) { 
1680             paramsAll 
<< paramTypes
[param
] << ' ' << paramNames
[param
]; 
1684         if (foundCommand 
== ConstFunc
) 
1685             constStr 
= _T(" const"); 
1687         wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'", 
1696         // store the info about the just found function 
1697         ArrayMethodInfo 
*methods
; 
1698         int index 
= m_classes
.Index(classname
); 
1699         if ( index 
== wxNOT_FOUND 
) { 
1700             m_classes
.Add(classname
); 
1702             methods 
= new ArrayMethodInfo
; 
1703             m_methods
.Add(methods
); 
1706             methods 
= m_methods
[(size_t)index
]; 
1709         ArrayParamInfo params
; 
1710         for ( param 
= 0; param 
< paramCount
; param
++ ) { 
1711             params
.Add(new ParamInfo(paramTypes
[param
], 
1713                                      paramValues
[param
])); 
1716         MethodInfo 
*method 
= new MethodInfo(returnType
, funcName
, params
); 
1717         if ( foundCommand 
== ConstFunc 
) 
1718             method
->SetFlag(MethodInfo::Const
); 
1720             method
->SetFlag(MethodInfo::Vararg
); 
1722         methods
->Add(method
); 
1727     wxLogVerbose("%s: finished parsing doc file '%s'.\n", 
1728                  GetCurrentTimeFormatted("%H:%M:%S"), m_filename
.c_str()); 
1733 bool DocManager::DumpDifferences(spContext 
*ctxTop
) const 
1735     typedef MMemberListT::const_iterator MemberIndex
; 
1737     bool foundDiff 
= false; 
1739     // flag telling us whether the given class was found at all in the header 
1740     size_t nClass
, countClassesInDocs 
= m_classes
.GetCount(); 
1741     bool *classExists 
= new bool[countClassesInDocs
]; 
1742     for ( nClass 
= 0; nClass 
< countClassesInDocs
; nClass
++ ) { 
1743         classExists
[nClass
] = false; 
1746     // ctxTop is normally an spFile 
1747     wxASSERT( ctxTop
->GetContextType() == SP_CTX_FILE 
); 
1749     const MMemberListT
& classes 
= ctxTop
->GetMembers(); 
1750     for ( MemberIndex i 
= classes
.begin(); i 
!= classes
.end(); i
++ ) { 
1751         spContext 
*ctx 
= *i
; 
1752         if ( ctx
->GetContextType() != SP_CTX_CLASS 
) { 
1753             // TODO process also global functions, macros, ... 
1757         spClass 
*ctxClass 
= (spClass 
*)ctx
; 
1758         const wxString
& nameClass 
= ctxClass
->m_Name
; 
1759         int index 
= m_classes
.Index(nameClass
); 
1760         if ( index 
== wxNOT_FOUND 
) { 
1761             if ( !m_ignoreNames
.IgnoreClass(nameClass
) ) { 
1764                 wxLogError("Class '%s' is not documented at all.", 
1768             // it makes no sense to check for its functions 
1772             classExists
[index
] = true; 
1775         // array of method descriptions for this class 
1776         const ArrayMethodInfo
& methods 
= *(m_methods
[index
]); 
1777         size_t nMethod
, countMethods 
= methods
.GetCount(); 
1779         // flags telling if we already processed given function 
1780         bool *methodExists 
= new bool[countMethods
]; 
1781         for ( nMethod 
= 0; nMethod 
< countMethods
; nMethod
++ ) { 
1782             methodExists
[nMethod
] = false; 
1785         wxArrayString aOverloadedMethods
; 
1787         const MMemberListT
& functions 
= ctxClass
->GetMembers(); 
1788         for ( MemberIndex j 
= functions
.begin(); j 
!= functions
.end(); j
++ ) { 
1790             if ( ctx
->GetContextType() != SP_CTX_OPERATION 
) 
1793             spOperation 
*ctxMethod 
= (spOperation 
*)ctx
; 
1794             const wxString
& nameMethod 
= ctxMethod
->m_Name
; 
1796             // find all functions with the same name 
1797             wxArrayInt aMethodsWithSameName
; 
1798             for ( nMethod 
= 0; nMethod 
< countMethods
; nMethod
++ ) { 
1799                 if ( methods
[nMethod
]->GetName() == nameMethod 
) 
1800                     aMethodsWithSameName
.Add(nMethod
); 
1803             if ( aMethodsWithSameName
.IsEmpty() && ctxMethod
->IsPublic() ) { 
1804                 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) { 
1807                     wxLogError("'%s::%s' is not documented.", 
1809                                nameMethod
.c_str()); 
1812                 // don't check params 
1815             else if ( aMethodsWithSameName
.GetCount() == 1 ) { 
1816                 index 
= (size_t)aMethodsWithSameName
[0u]; 
1817                 methodExists
[index
] = true; 
1819                 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) 
1822                 if ( !ctxMethod
->IsPublic() ) { 
1823                     wxLogWarning("'%s::%s' is documented but not public.", 
1825                                  nameMethod
.c_str()); 
1828                 // check that the flags match 
1829                 const MethodInfo
& method 
= *(methods
[index
]); 
1831                 bool isVirtual 
= ctxMethod
->mIsVirtual
; 
1832                 if ( isVirtual 
!= method
.HasFlag(MethodInfo::Virtual
) ) { 
1833                     wxLogWarning("'%s::%s' is incorrectly documented as %s" 
1837                                  isVirtual 
? "not " : ""); 
1840                 bool isConst 
= ctxMethod
->mIsConstant
; 
1841                 if ( isConst 
!= method
.HasFlag(MethodInfo::Const
) ) { 
1842                     wxLogWarning("'%s::%s' is incorrectly documented as %s" 
1846                                  isConst 
? "not " : ""); 
1849                 // check that the params match 
1850                 const MMemberListT
& params 
= ctxMethod
->GetMembers(); 
1852                 if ( params
.size() != method
.GetParamCount() ) { 
1853                     wxLogError("Incorrect number of parameters for '%s::%s' " 
1854                                "in the docs: should be %d instead of %d.", 
1857                                (int)params
.size(), (int)method
.GetParamCount()); 
1861                     for ( MemberIndex k 
= params
.begin(); 
1866                         // what else can a function have? 
1867                         wxASSERT( ctx
->GetContextType() == SP_CTX_PARAMETER 
); 
1869                         spParameter 
*ctxParam 
= (spParameter 
*)ctx
; 
1870                         const ParamInfo
& param 
= method
.GetParam(nParam
); 
1871                         if ( m_checkParamNames 
&& 
1872                              (param
.GetName() != ctxParam
->m_Name
.c_str()) ) { 
1875                             wxLogError("Parameter #%d of '%s::%s' should be " 
1876                                        "'%s' and not '%s'.", 
1880                                        ctxParam
->m_Name
.c_str(), 
1881                                        param
.GetName().c_str()); 
1886                         if ( param
.GetType() != ctxParam
->m_Type 
) { 
1889                             wxLogError("Type of parameter '%s' of '%s::%s' " 
1890                                        "should be '%s' and not '%s'.", 
1891                                        ctxParam
->m_Name
.c_str(), 
1894                                        ctxParam
->m_Type
.c_str(), 
1895                                        param
.GetType().GetName().c_str()); 
1900                         if ( param
.GetDefValue() != ctxParam
->m_InitVal
.c_str() ) { 
1901                             wxLogWarning("Default value of parameter '%s' of " 
1902                                          "'%s::%s' should be '%s' and not " 
1904                                          ctxParam
->m_Name
.c_str(), 
1907                                          ctxParam
->m_InitVal
.c_str(), 
1908                                          param
.GetDefValue().c_str()); 
1914                 // TODO OVER add real support for overloaded methods 
1916                 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) 
1919                 if ( aOverloadedMethods
.Index(nameMethod
) == wxNOT_FOUND 
) { 
1920                     // mark all methods with this name as existing 
1921                     for ( nMethod 
= 0; nMethod 
< countMethods
; nMethod
++ ) { 
1922                         if ( methods
[nMethod
]->GetName() == nameMethod 
) 
1923                             methodExists
[nMethod
] = true; 
1926                     aOverloadedMethods
.Add(nameMethod
); 
1928                     wxLogVerbose("'%s::%s' is overloaded and I'm too " 
1929                                  "stupid to find the right match - skipping " 
1930                                  "the param and flags checks.", 
1932                                  nameMethod
.c_str()); 
1934                 //else: warning already given 
1938         for ( nMethod 
= 0; nMethod 
< countMethods
; nMethod
++ ) { 
1939             if ( !methodExists
[nMethod
] ) { 
1940                 const wxString
& nameMethod 
= methods
[nMethod
]->GetName(); 
1941                 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) { 
1944                     wxLogError("'%s::%s' is documented but doesn't exist.", 
1946                                nameMethod
.c_str()); 
1951         delete [] methodExists
; 
1954     // check that all classes we found in the docs really exist 
1955     for ( nClass 
= 0; nClass 
< countClassesInDocs
; nClass
++ ) { 
1956         if ( !classExists
[nClass
] ) { 
1959             wxLogError("Class '%s' is documented but doesn't exist.", 
1960                        m_classes
[nClass
].c_str()); 
1964     delete [] classExists
; 
1969 DocManager::~DocManager() 
1971     WX_CLEAR_ARRAY(m_methods
); 
1974 // --------------------------------------------------------------------------- 
1975 // IgnoreNamesHandler implementation 
1976 // --------------------------------------------------------------------------- 
1978 int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry 
*first
, 
1979                                                  IgnoreListEntry 
*second
) 
1981     // first compare the classes 
1982     int rc 
= first
->m_classname
.Cmp(second
->m_classname
); 
1984         rc 
= first
->m_funcname
.Cmp(second
->m_funcname
); 
1989 bool IgnoreNamesHandler::AddNamesFromFile(const wxString
& filename
) 
1991     wxFile 
file(filename
, wxFile::read
); 
1992     if ( !file
.IsOpened() ) 
1995     off_t len 
= file
.Length(); 
1996     if ( len 
== wxInvalidOffset 
) 
1999     char *buf 
= new char[len 
+ 1]; 
2002     if ( file
.Read(buf
, len
) == wxInvalidOffset 
) { 
2009     for ( const char *current 
= buf
; ; current
++ ) { 
2011         // skip DOS line separator 
2012         if ( *current 
== '\r' ) 
2016         if ( *current 
== '\n' || *current 
== '\0' ) { 
2017             if ( line
[0u] != '#' ) { 
2018                 if ( line
.Find(':') != wxNOT_FOUND 
) { 
2019                     wxString classname 
= line
.BeforeFirst(':'), 
2020                              funcname 
= line
.AfterLast(':'); 
2021                     m_ignore
.Add(new IgnoreListEntry(classname
, funcname
)); 
2025                     m_ignore
.Add(new IgnoreListEntry(line
, wxEmptyString
)); 
2030             if ( *current 
== '\0' ) 
2045 // ----------------------------------------------------------------------------- 
2046 // global function implementation 
2047 // ----------------------------------------------------------------------------- 
2049 static wxString 
MakeLabel(const char *classname
, const char *funcname
) 
2051     wxString 
label(classname
); 
2052     if ( funcname 
&& funcname
[0] == '\\' ) { 
2053         // we may have some special TeX macro - so far only \destruct exists, 
2054         // but may be later others will be added 
2055         static const char *macros
[] = { "destruct" }; 
2056         static const char *replacement
[] = { "dtor" }; 
2059         for ( n 
= 0; n 
< WXSIZEOF(macros
); n
++ ) { 
2060             if ( strncmp(funcname 
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) { 
2066         if ( n 
== WXSIZEOF(macros
) ) { 
2067             wxLogWarning("unknown function name '%s' - leaving as is.", 
2071             funcname 
= replacement
[n
]; 
2076         // special treatment for operatorXXX() stuff because the C operators 
2077         // are not valid in LaTeX labels 
2079         if ( wxString(funcname
).StartsWith("operator", &oper
) ) { 
2080             label 
<< "operator"; 
2093             for ( n 
= 0; n 
< WXSIZEOF(operatorNames
); n
++ ) { 
2094                 if ( oper 
== operatorNames
[n
].oper 
) { 
2095                     label 
<< operatorNames
[n
].name
; 
2101             if ( n 
== WXSIZEOF(operatorNames
) ) { 
2102                 wxLogWarning("unknown operator '%s' - making dummy label.", 
2108         else // simply use the func name 
2119 static wxString 
MakeHelpref(const char *argument
) 
2122     helpref 
<< "\\helpref{" << argument 
<< "}{" << MakeLabel(argument
) << '}'; 
2127 static void TeXFilter(wxString
* str
) 
2129     // TeX special which can be quoted (don't include backslash nor braces as 
2131     static wxRegEx 
reNonSpecialSpecials("[#$%&_]"), 
2135     reNonSpecialSpecials
.ReplaceAll(str
, "\\\\\\0"); 
2137     // can't quote these ones as they produce accents when preceded by 
2138     // backslash, so put them inside verb 
2139     reAccents
.ReplaceAll(str
, "\\\\verb|\\0|"); 
2142 static void TeXUnfilter(wxString
* str
) 
2144     // FIXME may be done much more quickly 
2149     static wxRegEx 
reNonSpecialSpecials("\\\\([#$%&_{}])"), 
2150                    reAccents("\\\\verb\\|([~^])\\|"); 
2152     reNonSpecialSpecials
.ReplaceAll(str
, "\\1"); 
2153     reAccents
.ReplaceAll(str
, "\\1"); 
2156 static wxString 
GetAllComments(const spContext
& ctx
) 
2159     const MCommentListT
& commentsList 
= ctx
.GetCommentList(); 
2160     for ( MCommentListT::const_iterator i 
= commentsList
.begin(); 
2161           i 
!= commentsList
.end(); 
2163         wxString comment 
= (*i
)->GetText(); 
2165         // don't take comments like "// ----------" &c 
2166         comment
.Trim(false); 
2167         if ( !comment
.empty() && 
2168               comment 
== wxString(comment
[0u], comment
.length() - 1) + '\n' ) 
2171             comments 
<< comment
; 
2177 static const char *GetCurrentTimeFormatted(const char *timeFormat
) 
2179     static char s_timeBuffer
[128]; 
2184     ptmNow 
= localtime(&timeNow
); 
2186     strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
); 
2188     return s_timeBuffer
; 
2191 static const wxString 
GetVersionString() 
2193     wxString version 
= "$Revision$"; 
2194     wxRegEx("^\\$Revision$$").ReplaceFirst(&version
, "\\1"); 
2200    Revision 1.43  2005/05/31 15:42:43  ABX 
2201    More warning and error fixes (work in progress with Tinderbox). 
2203    Revision 1.42  2005/05/31 15:32:49  ABX 
2204    More warning and error fixes (work in progress with Tinderbox). 
2206    Revision 1.41  2005/05/30 13:06:15  ABX 
2207    More warning and error fixes (work in progress with Tinderbox). 
2209    Revision 1.40  2005/05/30 11:49:32  ABX 
2210    More warning and error fixes (work in progress with Tinderbox). 
2212    Revision 1.39  2005/05/30 09:26:42  ABX 
2213    More warning and error fixes (work in progress with Tinderbox). 
2215    Revision 1.38  2005/05/24 09:06:20  ABX 
2216    More fixes and wxWidgets coding standards. 
2218    Revision 1.37  2005/05/23 15:22:08  ABX 
2219    Initial HelpGen source cleaning. 
2221    Revision 1.36  2005/04/07 19:54:58  MW 
2222    Workarounds to allow compilation by Sun C++ 5.5 
2224    Revision 1.35  2004/12/12 11:03:31  VZ 
2225    give an error message if we're built in Unicode mode (in response to bug 1079224) 
2227    Revision 1.34  2004/11/23 09:53:31  JS 
2228    Changed GPL to wxWindows Licence 
2230    Revision 1.33  2004/11/12 03:30:07  RL 
2232    Cruft cleanup from MJW, strip the tabs out of sound.cpp 
2234    Revision 1.32  2004/11/10 21:02:58  VZ 
2235    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) 
2237    Revision 1.31  2004/10/05 15:38:29  ABX 
2238    Warning fixes found under hardest mode of OpenWatcom. Seems clean in Borland, MinGW and DMC. 
2240    Revision 1.30  2004/06/18 19:25:50  ABX 
2241    Small step in making HelpGen up to date unicode application. 
2243    Revision 1.29  2004/06/17 19:00:22  ABX 
2244    Warning fixes. Code cleanup. Whitespaces and tabs removed. 
2246    Revision 1.28  2004/05/25 11:19:57  JS 
2249    Revision 1.27  2003/10/13 17:21:30  MBN 
2252    Revision 1.26  2003/09/29 15:18:35  MBN 
2253      (Blind) compilation fix for Sun compiler. 
2255    Revision 1.25  2003/09/03 17:39:27  MBN 
2258    Revision 1.24  2003/08/13 22:59:37  VZ 
2261    Revision 1.23  2003/06/13 17:05:43  VZ 
2262    quote '|' inside regexes (fixes dump mode); fixed crash due to strange HelpGenApp code 
2264    Revision 1.22  2002/01/21 21:18:50  JS 
2265    Now adds 'include file' heading 
2267    Revision 1.21  2002/01/04 11:06:09  JS 
2268    Fixed missing membersections bug and also bug with functions not being written 
2271    Revision 1.20  2002/01/03 14:23:33  JS 
2272    Added code to make it not duplicate membersections for overloaded functions 
2274    Revision 1.19  2002/01/03 13:34:12  JS 
2275    Added FlushAll to CloseClass, otherwise text was only flushed right at the end, 
2276    and appeared in one file. 
2278    Revision 1.18  2002/01/03 12:02:47  JS 
2279    Added main() and corrected VC++ project settings 
2281    Revision 1.17  2001/11/30 21:43:35  VZ 
2282    now the methods are sorted in the correct order in the generated docs 
2284    Revision 1.16  2001/11/28 19:27:33  VZ 
2285    HelpGen doesn't work in GUI mode 
2287    Revision 1.15  2001/11/22 21:59:58  GD 
2288    use "..." instead of <...> for wx headers 
2290    Revision 1.14  2001/07/19 13:51:29  VZ 
2291    fixes to version string 
2293    Revision 1.13  2001/07/19 13:44:57  VZ 
2294    1. compilation fixes 
2295    2. don't quote special characters inside verbatim environment 
2297    Revision 1.12  2000/10/09 13:53:33  juliansmart 
2299    Doc corrections; added HelpGen project files 
2301    Revision 1.11  2000/07/15 19:50:42  cvsuser 
2304    Revision 1.10.2.2  2000/03/27 15:33:10  VZ 
2305    don't trasnform output dir name to lower case 
2307    Revision 1.10  2000/03/11 10:05:23  VS 
2308    now compiles with wxBase 
2310    Revision 1.9  2000/01/16 13:25:21  VS 
2311    compilation fixes (gcc) 
2313    Revision 1.8  1999/09/13 14:29:39  JS 
2315    Made HelpGen into a wxWin app (still uses command-line args); moved includes 
2316    into src for simplicity; added VC++ 5 project file 
2318    Revision 1.7  1999/02/21 22:32:32  VZ 
2319    1. more C++ parser fixes - now it almost parses wx/string.h 
2320     a) #if/#ifdef/#else (very) limited support 
2321     b) param type fix - now indirection chars are correctly handled 
2322     c) class/struct/union distinction 
2323     d) public/private fixes 
2324     e) Dump() function added - very useful for debugging 
2326    2. option to ignore parameter names during 'diff' (in fact, they're ignored 
2327       by default, and this option switches it on) 
2329    Revision 1.6  1999/02/20 23:00:26  VZ 
2330    1. new 'diff' mode which seems to work 
2331    2. output files are not overwritten in 'dmup' mode 
2332    3. fixes for better handling of const functions and operators 
2333     ---------------------------- 
2335     date: 1999/02/15 23:07:25;  author: VZ;  state: Exp;  lines: +106 -45 
2336     1. Parser improvements 
2337      a) const and virtual methods are parsed correctly (not static yet) 
2338      b) "const" which is part of the return type is not swallowed 
2340     2. HelpGen improvements: -o outputdir parameter added to the cmd line, 
2341        "//---------" kind comments discarded now. 
2342     ---------------------------- 
2344     date: 1999/01/13 14:23:31;  author: JS;  state: Exp;  lines: +4 -4 
2346     some tweaks to HelpGen 
2347     ---------------------------- 
2349     date: 1999/01/09 20:18:03;  author: JS;  state: Exp;  lines: +7 -2 
2351     HelpGen starting to compile with VC++ 
2352     ---------------------------- 
2354     date: 1999/01/08 19:46:22;  author: VZ;  state: Exp;  lines: +208 -35 
2356     supports typedefs, generates "See also:" and adds "virtual " for virtual 
2358     ---------------------------- 
2360     date: 1999/01/08 17:45:55;  author: VZ;  state: Exp; 
2362     HelpGen is a prototype of the tool for automatic generation of the .tex files 
2363     for wxWidgets documentation from C++ headers 
2366 /* vi: set tw=80 et ts=4 sw=4: */