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
, _T(""));
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
.IsEmpty() ) {
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
.IsEmpty() && 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
);
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
.IsEmpty() )
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
= "";
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
.IsEmpty() ) {
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
, & 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
.mSuperClassNames
;
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
<< "\\begin{verbatim}\n"
1168 << "\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
<< "{\\small \\begin{verbatim}\n"
1198 << "typedef " << td
.mOriginalType
<< ' ' << td
.GetName()
1199 << "\n\\end{verbatim}}\n"
1200 << GetAllComments(td
);
1202 // remember for later use if we're not inside a class yet
1204 if ( !m_textStoredTypedefs
.IsEmpty() ) {
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
.mRetType
.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
.mType
<< " }{" << param
.GetName();
1321 wxString defvalue
= param
.mInitVal
;
1322 if ( !defvalue
.IsEmpty() ) {
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(), 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(), 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(), 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(), 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(), 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(), 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(), 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(), 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(), 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(), 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
) {
1619 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1620 if ( !!paramText
) {
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(), 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(), 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
];
1683 wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
1684 m_filename
.c_str(), m_line
,
1689 foundCommand
== ConstFunc
? " const" : "");
1691 // store the info about the just found function
1692 ArrayMethodInfo
*methods
;
1693 int index
= m_classes
.Index(classname
);
1694 if ( index
== wxNOT_FOUND
) {
1695 m_classes
.Add(classname
);
1697 methods
= new ArrayMethodInfo
;
1698 m_methods
.Add(methods
);
1701 methods
= m_methods
[(size_t)index
];
1704 ArrayParamInfo params
;
1705 for ( param
= 0; param
< paramCount
; param
++ ) {
1706 params
.Add(new ParamInfo(paramTypes
[param
],
1708 paramValues
[param
]));
1711 MethodInfo
*method
= new MethodInfo(returnType
, funcName
, params
);
1712 if ( foundCommand
== ConstFunc
)
1713 method
->SetFlag(MethodInfo::Const
);
1715 method
->SetFlag(MethodInfo::Vararg
);
1717 methods
->Add(method
);
1722 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1723 GetCurrentTimeFormatted("%H:%M:%S"), m_filename
.c_str());
1728 bool DocManager::DumpDifferences(spContext
*ctxTop
) const
1730 typedef MMemberListT::const_iterator MemberIndex
;
1732 bool foundDiff
= false;
1734 // flag telling us whether the given class was found at all in the header
1735 size_t nClass
, countClassesInDocs
= m_classes
.GetCount();
1736 bool *classExists
= new bool[countClassesInDocs
];
1737 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1738 classExists
[nClass
] = false;
1741 // ctxTop is normally an spFile
1742 wxASSERT( ctxTop
->GetContextType() == SP_CTX_FILE
);
1744 const MMemberListT
& classes
= ctxTop
->GetMembers();
1745 for ( MemberIndex i
= classes
.begin(); i
!= classes
.end(); i
++ ) {
1746 spContext
*ctx
= *i
;
1747 if ( ctx
->GetContextType() != SP_CTX_CLASS
) {
1748 // TODO process also global functions, macros, ...
1752 spClass
*ctxClass
= (spClass
*)ctx
;
1753 const wxString
& nameClass
= ctxClass
->mName
;
1754 int index
= m_classes
.Index(nameClass
);
1755 if ( index
== wxNOT_FOUND
) {
1756 if ( !m_ignoreNames
.IgnoreClass(nameClass
) ) {
1759 wxLogError("Class '%s' is not documented at all.",
1763 // it makes no sense to check for its functions
1767 classExists
[index
] = true;
1770 // array of method descriptions for this class
1771 const ArrayMethodInfo
& methods
= *(m_methods
[index
]);
1772 size_t nMethod
, countMethods
= methods
.GetCount();
1774 // flags telling if we already processed given function
1775 bool *methodExists
= new bool[countMethods
];
1776 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1777 methodExists
[nMethod
] = false;
1780 wxArrayString aOverloadedMethods
;
1782 const MMemberListT
& functions
= ctxClass
->GetMembers();
1783 for ( MemberIndex j
= functions
.begin(); j
!= functions
.end(); j
++ ) {
1785 if ( ctx
->GetContextType() != SP_CTX_OPERATION
)
1788 spOperation
*ctxMethod
= (spOperation
*)ctx
;
1789 const wxString
& nameMethod
= ctxMethod
->mName
;
1791 // find all functions with the same name
1792 wxArrayInt aMethodsWithSameName
;
1793 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1794 if ( methods
[nMethod
]->GetName() == nameMethod
)
1795 aMethodsWithSameName
.Add(nMethod
);
1798 if ( aMethodsWithSameName
.IsEmpty() && ctxMethod
->IsPublic() ) {
1799 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1802 wxLogError("'%s::%s' is not documented.",
1804 nameMethod
.c_str());
1807 // don't check params
1810 else if ( aMethodsWithSameName
.GetCount() == 1 ) {
1811 index
= (size_t)aMethodsWithSameName
[0u];
1812 methodExists
[index
] = true;
1814 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1817 if ( !ctxMethod
->IsPublic() ) {
1818 wxLogWarning("'%s::%s' is documented but not public.",
1820 nameMethod
.c_str());
1823 // check that the flags match
1824 const MethodInfo
& method
= *(methods
[index
]);
1826 bool isVirtual
= ctxMethod
->mIsVirtual
;
1827 if ( isVirtual
!= method
.HasFlag(MethodInfo::Virtual
) ) {
1828 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1832 isVirtual
? "not " : "");
1835 bool isConst
= ctxMethod
->mIsConstant
;
1836 if ( isConst
!= method
.HasFlag(MethodInfo::Const
) ) {
1837 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1841 isConst
? "not " : "");
1844 // check that the params match
1845 const MMemberListT
& params
= ctxMethod
->GetMembers();
1847 if ( params
.size() != method
.GetParamCount() ) {
1848 wxLogError("Incorrect number of parameters for '%s::%s' "
1849 "in the docs: should be %d instead of %d.",
1852 params
.size(), method
.GetParamCount());
1856 for ( MemberIndex k
= params
.begin();
1861 // what else can a function have?
1862 wxASSERT( ctx
->GetContextType() == SP_CTX_PARAMETER
);
1864 spParameter
*ctxParam
= (spParameter
*)ctx
;
1865 const ParamInfo
& param
= method
.GetParam(nParam
);
1866 if ( m_checkParamNames
&&
1867 (param
.GetName() != ctxParam
->mName
.c_str()) ) {
1870 wxLogError("Parameter #%d of '%s::%s' should be "
1871 "'%s' and not '%s'.",
1875 ctxParam
->mName
.c_str(),
1876 param
.GetName().c_str());
1881 if ( param
.GetType() != ctxParam
->mType
) {
1884 wxLogError("Type of parameter '%s' of '%s::%s' "
1885 "should be '%s' and not '%s'.",
1886 ctxParam
->mName
.c_str(),
1889 ctxParam
->mType
.c_str(),
1890 param
.GetType().GetName().c_str());
1895 if ( param
.GetDefValue() != ctxParam
->mInitVal
.c_str() ) {
1896 wxLogWarning("Default value of parameter '%s' of "
1897 "'%s::%s' should be '%s' and not "
1899 ctxParam
->mName
.c_str(),
1902 ctxParam
->mInitVal
.c_str(),
1903 param
.GetDefValue().c_str());
1909 // TODO OVER add real support for overloaded methods
1911 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1914 if ( aOverloadedMethods
.Index(nameMethod
) == wxNOT_FOUND
) {
1915 // mark all methods with this name as existing
1916 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1917 if ( methods
[nMethod
]->GetName() == nameMethod
)
1918 methodExists
[nMethod
] = true;
1921 aOverloadedMethods
.Add(nameMethod
);
1923 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1924 "stupid to find the right match - skipping "
1925 "the param and flags checks.",
1927 nameMethod
.c_str());
1929 //else: warning already given
1933 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1934 if ( !methodExists
[nMethod
] ) {
1935 const wxString
& nameMethod
= methods
[nMethod
]->GetName();
1936 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1939 wxLogError("'%s::%s' is documented but doesn't exist.",
1941 nameMethod
.c_str());
1946 delete [] methodExists
;
1949 // check that all classes we found in the docs really exist
1950 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1951 if ( !classExists
[nClass
] ) {
1954 wxLogError("Class '%s' is documented but doesn't exist.",
1955 m_classes
[nClass
].c_str());
1959 delete [] classExists
;
1964 DocManager::~DocManager()
1966 WX_CLEAR_ARRAY(m_methods
);
1969 // ---------------------------------------------------------------------------
1970 // IgnoreNamesHandler implementation
1971 // ---------------------------------------------------------------------------
1973 int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry
*first
,
1974 IgnoreListEntry
*second
)
1976 // first compare the classes
1977 int rc
= first
->m_classname
.Cmp(second
->m_classname
);
1979 rc
= first
->m_funcname
.Cmp(second
->m_funcname
);
1984 bool IgnoreNamesHandler::AddNamesFromFile(const wxString
& filename
)
1986 wxFile
file(filename
, wxFile::read
);
1987 if ( !file
.IsOpened() )
1990 off_t len
= file
.Length();
1991 if ( len
== wxInvalidOffset
)
1994 char *buf
= new char[len
+ 1];
1997 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
2004 for ( const char *current
= buf
; ; current
++ ) {
2006 // skip DOS line separator
2007 if ( *current
== '\r' )
2011 if ( *current
== '\n' || *current
== '\0' ) {
2012 if ( line
[0u] != '#' ) {
2013 if ( line
.Find(':') != wxNOT_FOUND
) {
2014 wxString classname
= line
.BeforeFirst(':'),
2015 funcname
= line
.AfterLast(':');
2016 m_ignore
.Add(new IgnoreListEntry(classname
, funcname
));
2020 m_ignore
.Add(new IgnoreListEntry(line
, ""));
2025 if ( *current
== '\0' )
2040 // -----------------------------------------------------------------------------
2041 // global function implementation
2042 // -----------------------------------------------------------------------------
2044 static wxString
MakeLabel(const char *classname
, const char *funcname
)
2046 wxString
label(classname
);
2047 if ( funcname
&& funcname
[0] == '\\' ) {
2048 // we may have some special TeX macro - so far only \destruct exists,
2049 // but may be later others will be added
2050 static const char *macros
[] = { "destruct" };
2051 static const char *replacement
[] = { "dtor" };
2054 for ( n
= 0; n
< WXSIZEOF(macros
); n
++ ) {
2055 if ( strncmp(funcname
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) {
2061 if ( n
== WXSIZEOF(macros
) ) {
2062 wxLogWarning("unknown function name '%s' - leaving as is.",
2066 funcname
= replacement
[n
];
2071 // special treatment for operatorXXX() stuff because the C operators
2072 // are not valid in LaTeX labels
2074 if ( wxString(funcname
).StartsWith("operator", &oper
) ) {
2075 label
<< "operator";
2088 for ( n
= 0; n
< WXSIZEOF(operatorNames
); n
++ ) {
2089 if ( oper
== operatorNames
[n
].oper
) {
2090 label
<< operatorNames
[n
].name
;
2096 if ( n
== WXSIZEOF(operatorNames
) ) {
2097 wxLogWarning("unknown operator '%s' - making dummy label.",
2103 else // simply use the func name
2114 static wxString
MakeHelpref(const char *argument
)
2117 helpref
<< "\\helpref{" << argument
<< "}{" << MakeLabel(argument
) << '}';
2122 static void TeXFilter(wxString
* str
)
2124 // TeX special which can be quoted (don't include backslash nor braces as
2126 static wxRegEx
reNonSpecialSpecials("[#$%&_]"),
2130 reNonSpecialSpecials
.ReplaceAll(str
, "\\\\\\0");
2132 // can't quote these ones as they produce accents when preceded by
2133 // backslash, so put them inside verb
2134 reAccents
.ReplaceAll(str
, "\\\\verb|\\0|");
2137 static void TeXUnfilter(wxString
* str
)
2139 // FIXME may be done much more quickly
2144 static wxRegEx
reNonSpecialSpecials("\\\\([#$%&_{}])"),
2145 reAccents("\\\\verb\\|([~^])\\|");
2147 reNonSpecialSpecials
.ReplaceAll(str
, "\\1");
2148 reAccents
.ReplaceAll(str
, "\\1");
2151 static wxString
GetAllComments(const spContext
& ctx
)
2154 const MCommentListT
& commentsList
= ctx
.GetCommentList();
2155 for ( MCommentListT::const_iterator i
= commentsList
.begin();
2156 i
!= commentsList
.end();
2158 wxString comment
= (*i
)->GetText();
2160 // don't take comments like "// ----------" &c
2161 comment
.Trim(false);
2163 comment
== wxString(comment
[0u], comment
.length() - 1) + '\n' )
2166 comments
<< comment
;
2172 static const char *GetCurrentTimeFormatted(const char *timeFormat
)
2174 static char s_timeBuffer
[128];
2179 ptmNow
= localtime(&timeNow
);
2181 strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
);
2183 return s_timeBuffer
;
2186 static const wxString
GetVersionString()
2188 wxString version
= "$Revision$";
2189 wxRegEx("^\\$Revision$$").ReplaceFirst(&version
, "\\1");
2195 Revision 1.36 2005/04/07 19:54:58 MW
2196 Workarounds to allow compilation by Sun C++ 5.5
2198 Revision 1.35 2004/12/12 11:03:31 VZ
2199 give an error message if we're built in Unicode mode (in response to bug 1079224)
2201 Revision 1.34 2004/11/23 09:53:31 JS
2202 Changed GPL to wxWindows Licence
2204 Revision 1.33 2004/11/12 03:30:07 RL
2206 Cruft cleanup from MJW, strip the tabs out of sound.cpp
2208 Revision 1.32 2004/11/10 21:02:58 VZ
2209 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)
2211 Revision 1.31 2004/10/05 15:38:29 ABX
2212 Warning fixes found under hardest mode of OpenWatcom. Seems clean in Borland, MinGW and DMC.
2214 Revision 1.30 2004/06/18 19:25:50 ABX
2215 Small step in making HelpGen up to date unicode application.
2217 Revision 1.29 2004/06/17 19:00:22 ABX
2218 Warning fixes. Code cleanup. Whitespaces and tabs removed.
2220 Revision 1.28 2004/05/25 11:19:57 JS
2223 Revision 1.27 2003/10/13 17:21:30 MBN
2226 Revision 1.26 2003/09/29 15:18:35 MBN
2227 (Blind) compilation fix for Sun compiler.
2229 Revision 1.25 2003/09/03 17:39:27 MBN
2232 Revision 1.24 2003/08/13 22:59:37 VZ
2235 Revision 1.23 2003/06/13 17:05:43 VZ
2236 quote '|' inside regexes (fixes dump mode); fixed crash due to strange HelpGenApp code
2238 Revision 1.22 2002/01/21 21:18:50 JS
2239 Now adds 'include file' heading
2241 Revision 1.21 2002/01/04 11:06:09 JS
2242 Fixed missing membersections bug and also bug with functions not being written
2245 Revision 1.20 2002/01/03 14:23:33 JS
2246 Added code to make it not duplicate membersections for overloaded functions
2248 Revision 1.19 2002/01/03 13:34:12 JS
2249 Added FlushAll to CloseClass, otherwise text was only flushed right at the end,
2250 and appeared in one file.
2252 Revision 1.18 2002/01/03 12:02:47 JS
2253 Added main() and corrected VC++ project settings
2255 Revision 1.17 2001/11/30 21:43:35 VZ
2256 now the methods are sorted in the correct order in the generated docs
2258 Revision 1.16 2001/11/28 19:27:33 VZ
2259 HelpGen doesn't work in GUI mode
2261 Revision 1.15 2001/11/22 21:59:58 GD
2262 use "..." instead of <...> for wx headers
2264 Revision 1.14 2001/07/19 13:51:29 VZ
2265 fixes to version string
2267 Revision 1.13 2001/07/19 13:44:57 VZ
2268 1. compilation fixes
2269 2. don't quote special characters inside verbatim environment
2271 Revision 1.12 2000/10/09 13:53:33 juliansmart
2273 Doc corrections; added HelpGen project files
2275 Revision 1.11 2000/07/15 19:50:42 cvsuser
2278 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
2279 don't trasnform output dir name to lower case
2281 Revision 1.10 2000/03/11 10:05:23 VS
2282 now compiles with wxBase
2284 Revision 1.9 2000/01/16 13:25:21 VS
2285 compilation fixes (gcc)
2287 Revision 1.8 1999/09/13 14:29:39 JS
2289 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2290 into src for simplicity; added VC++ 5 project file
2292 Revision 1.7 1999/02/21 22:32:32 VZ
2293 1. more C++ parser fixes - now it almost parses wx/string.h
2294 a) #if/#ifdef/#else (very) limited support
2295 b) param type fix - now indirection chars are correctly handled
2296 c) class/struct/union distinction
2297 d) public/private fixes
2298 e) Dump() function added - very useful for debugging
2300 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2301 by default, and this option switches it on)
2303 Revision 1.6 1999/02/20 23:00:26 VZ
2304 1. new 'diff' mode which seems to work
2305 2. output files are not overwritten in 'dmup' mode
2306 3. fixes for better handling of const functions and operators
2307 ----------------------------
2309 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2310 1. Parser improvements
2311 a) const and virtual methods are parsed correctly (not static yet)
2312 b) "const" which is part of the return type is not swallowed
2314 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2315 "//---------" kind comments discarded now.
2316 ----------------------------
2318 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2320 some tweaks to HelpGen
2321 ----------------------------
2323 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2325 HelpGen starting to compile with VC++
2326 ----------------------------
2328 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2330 supports typedefs, generates "See also:" and adds "virtual " for virtual
2332 ----------------------------
2334 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2336 HelpGen is a prototype of the tool for automatic generation of the .tex files
2337 for wxWidgets documentation from C++ headers
2340 /* vi: set tw=80 et ts=4 sw=4: */