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
.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
);
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
= "";
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
.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
.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
.mInitVal
;
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'",
1688 m_filename
.c_str(), m_line
,
1695 // store the info about the just found function
1696 ArrayMethodInfo
*methods
;
1697 int index
= m_classes
.Index(classname
);
1698 if ( index
== wxNOT_FOUND
) {
1699 m_classes
.Add(classname
);
1701 methods
= new ArrayMethodInfo
;
1702 m_methods
.Add(methods
);
1705 methods
= m_methods
[(size_t)index
];
1708 ArrayParamInfo params
;
1709 for ( param
= 0; param
< paramCount
; param
++ ) {
1710 params
.Add(new ParamInfo(paramTypes
[param
],
1712 paramValues
[param
]));
1715 MethodInfo
*method
= new MethodInfo(returnType
, funcName
, params
);
1716 if ( foundCommand
== ConstFunc
)
1717 method
->SetFlag(MethodInfo::Const
);
1719 method
->SetFlag(MethodInfo::Vararg
);
1721 methods
->Add(method
);
1726 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1727 GetCurrentTimeFormatted("%H:%M:%S"), m_filename
.c_str());
1732 bool DocManager::DumpDifferences(spContext
*ctxTop
) const
1734 typedef MMemberListT::const_iterator MemberIndex
;
1736 bool foundDiff
= false;
1738 // flag telling us whether the given class was found at all in the header
1739 size_t nClass
, countClassesInDocs
= m_classes
.GetCount();
1740 bool *classExists
= new bool[countClassesInDocs
];
1741 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1742 classExists
[nClass
] = false;
1745 // ctxTop is normally an spFile
1746 wxASSERT( ctxTop
->GetContextType() == SP_CTX_FILE
);
1748 const MMemberListT
& classes
= ctxTop
->GetMembers();
1749 for ( MemberIndex i
= classes
.begin(); i
!= classes
.end(); i
++ ) {
1750 spContext
*ctx
= *i
;
1751 if ( ctx
->GetContextType() != SP_CTX_CLASS
) {
1752 // TODO process also global functions, macros, ...
1756 spClass
*ctxClass
= (spClass
*)ctx
;
1757 const wxString
& nameClass
= ctxClass
->m_Name
;
1758 int index
= m_classes
.Index(nameClass
);
1759 if ( index
== wxNOT_FOUND
) {
1760 if ( !m_ignoreNames
.IgnoreClass(nameClass
) ) {
1763 wxLogError("Class '%s' is not documented at all.",
1767 // it makes no sense to check for its functions
1771 classExists
[index
] = true;
1774 // array of method descriptions for this class
1775 const ArrayMethodInfo
& methods
= *(m_methods
[index
]);
1776 size_t nMethod
, countMethods
= methods
.GetCount();
1778 // flags telling if we already processed given function
1779 bool *methodExists
= new bool[countMethods
];
1780 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1781 methodExists
[nMethod
] = false;
1784 wxArrayString aOverloadedMethods
;
1786 const MMemberListT
& functions
= ctxClass
->GetMembers();
1787 for ( MemberIndex j
= functions
.begin(); j
!= functions
.end(); j
++ ) {
1789 if ( ctx
->GetContextType() != SP_CTX_OPERATION
)
1792 spOperation
*ctxMethod
= (spOperation
*)ctx
;
1793 const wxString
& nameMethod
= ctxMethod
->m_Name
;
1795 // find all functions with the same name
1796 wxArrayInt aMethodsWithSameName
;
1797 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1798 if ( methods
[nMethod
]->GetName() == nameMethod
)
1799 aMethodsWithSameName
.Add(nMethod
);
1802 if ( aMethodsWithSameName
.IsEmpty() && ctxMethod
->IsPublic() ) {
1803 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1806 wxLogError("'%s::%s' is not documented.",
1808 nameMethod
.c_str());
1811 // don't check params
1814 else if ( aMethodsWithSameName
.GetCount() == 1 ) {
1815 index
= (size_t)aMethodsWithSameName
[0u];
1816 methodExists
[index
] = true;
1818 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1821 if ( !ctxMethod
->IsPublic() ) {
1822 wxLogWarning("'%s::%s' is documented but not public.",
1824 nameMethod
.c_str());
1827 // check that the flags match
1828 const MethodInfo
& method
= *(methods
[index
]);
1830 bool isVirtual
= ctxMethod
->mIsVirtual
;
1831 if ( isVirtual
!= method
.HasFlag(MethodInfo::Virtual
) ) {
1832 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1836 isVirtual
? "not " : "");
1839 bool isConst
= ctxMethod
->mIsConstant
;
1840 if ( isConst
!= method
.HasFlag(MethodInfo::Const
) ) {
1841 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1845 isConst
? "not " : "");
1848 // check that the params match
1849 const MMemberListT
& params
= ctxMethod
->GetMembers();
1851 if ( params
.size() != method
.GetParamCount() ) {
1852 wxLogError("Incorrect number of parameters for '%s::%s' "
1853 "in the docs: should be %d instead of %d.",
1856 (int)params
.size(), (int)method
.GetParamCount());
1860 for ( MemberIndex k
= params
.begin();
1865 // what else can a function have?
1866 wxASSERT( ctx
->GetContextType() == SP_CTX_PARAMETER
);
1868 spParameter
*ctxParam
= (spParameter
*)ctx
;
1869 const ParamInfo
& param
= method
.GetParam(nParam
);
1870 if ( m_checkParamNames
&&
1871 (param
.GetName() != ctxParam
->m_Name
.c_str()) ) {
1874 wxLogError("Parameter #%d of '%s::%s' should be "
1875 "'%s' and not '%s'.",
1879 ctxParam
->m_Name
.c_str(),
1880 param
.GetName().c_str());
1885 if ( param
.GetType() != ctxParam
->m_Type
) {
1888 wxLogError("Type of parameter '%s' of '%s::%s' "
1889 "should be '%s' and not '%s'.",
1890 ctxParam
->m_Name
.c_str(),
1893 ctxParam
->m_Type
.c_str(),
1894 param
.GetType().GetName().c_str());
1899 if ( param
.GetDefValue() != ctxParam
->mInitVal
.c_str() ) {
1900 wxLogWarning("Default value of parameter '%s' of "
1901 "'%s::%s' should be '%s' and not "
1903 ctxParam
->m_Name
.c_str(),
1906 ctxParam
->mInitVal
.c_str(),
1907 param
.GetDefValue().c_str());
1913 // TODO OVER add real support for overloaded methods
1915 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1918 if ( aOverloadedMethods
.Index(nameMethod
) == wxNOT_FOUND
) {
1919 // mark all methods with this name as existing
1920 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1921 if ( methods
[nMethod
]->GetName() == nameMethod
)
1922 methodExists
[nMethod
] = true;
1925 aOverloadedMethods
.Add(nameMethod
);
1927 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1928 "stupid to find the right match - skipping "
1929 "the param and flags checks.",
1931 nameMethod
.c_str());
1933 //else: warning already given
1937 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1938 if ( !methodExists
[nMethod
] ) {
1939 const wxString
& nameMethod
= methods
[nMethod
]->GetName();
1940 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1943 wxLogError("'%s::%s' is documented but doesn't exist.",
1945 nameMethod
.c_str());
1950 delete [] methodExists
;
1953 // check that all classes we found in the docs really exist
1954 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1955 if ( !classExists
[nClass
] ) {
1958 wxLogError("Class '%s' is documented but doesn't exist.",
1959 m_classes
[nClass
].c_str());
1963 delete [] classExists
;
1968 DocManager::~DocManager()
1970 WX_CLEAR_ARRAY(m_methods
);
1973 // ---------------------------------------------------------------------------
1974 // IgnoreNamesHandler implementation
1975 // ---------------------------------------------------------------------------
1977 int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry
*first
,
1978 IgnoreListEntry
*second
)
1980 // first compare the classes
1981 int rc
= first
->m_classname
.Cmp(second
->m_classname
);
1983 rc
= first
->m_funcname
.Cmp(second
->m_funcname
);
1988 bool IgnoreNamesHandler::AddNamesFromFile(const wxString
& filename
)
1990 wxFile
file(filename
, wxFile::read
);
1991 if ( !file
.IsOpened() )
1994 off_t len
= file
.Length();
1995 if ( len
== wxInvalidOffset
)
1998 char *buf
= new char[len
+ 1];
2001 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
2008 for ( const char *current
= buf
; ; current
++ ) {
2010 // skip DOS line separator
2011 if ( *current
== '\r' )
2015 if ( *current
== '\n' || *current
== '\0' ) {
2016 if ( line
[0u] != '#' ) {
2017 if ( line
.Find(':') != wxNOT_FOUND
) {
2018 wxString classname
= line
.BeforeFirst(':'),
2019 funcname
= line
.AfterLast(':');
2020 m_ignore
.Add(new IgnoreListEntry(classname
, funcname
));
2024 m_ignore
.Add(new IgnoreListEntry(line
, ""));
2029 if ( *current
== '\0' )
2044 // -----------------------------------------------------------------------------
2045 // global function implementation
2046 // -----------------------------------------------------------------------------
2048 static wxString
MakeLabel(const char *classname
, const char *funcname
)
2050 wxString
label(classname
);
2051 if ( funcname
&& funcname
[0] == '\\' ) {
2052 // we may have some special TeX macro - so far only \destruct exists,
2053 // but may be later others will be added
2054 static const char *macros
[] = { "destruct" };
2055 static const char *replacement
[] = { "dtor" };
2058 for ( n
= 0; n
< WXSIZEOF(macros
); n
++ ) {
2059 if ( strncmp(funcname
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) {
2065 if ( n
== WXSIZEOF(macros
) ) {
2066 wxLogWarning("unknown function name '%s' - leaving as is.",
2070 funcname
= replacement
[n
];
2075 // special treatment for operatorXXX() stuff because the C operators
2076 // are not valid in LaTeX labels
2078 if ( wxString(funcname
).StartsWith("operator", &oper
) ) {
2079 label
<< "operator";
2092 for ( n
= 0; n
< WXSIZEOF(operatorNames
); n
++ ) {
2093 if ( oper
== operatorNames
[n
].oper
) {
2094 label
<< operatorNames
[n
].name
;
2100 if ( n
== WXSIZEOF(operatorNames
) ) {
2101 wxLogWarning("unknown operator '%s' - making dummy label.",
2107 else // simply use the func name
2118 static wxString
MakeHelpref(const char *argument
)
2121 helpref
<< "\\helpref{" << argument
<< "}{" << MakeLabel(argument
) << '}';
2126 static void TeXFilter(wxString
* str
)
2128 // TeX special which can be quoted (don't include backslash nor braces as
2130 static wxRegEx
reNonSpecialSpecials("[#$%&_]"),
2134 reNonSpecialSpecials
.ReplaceAll(str
, "\\\\\\0");
2136 // can't quote these ones as they produce accents when preceded by
2137 // backslash, so put them inside verb
2138 reAccents
.ReplaceAll(str
, "\\\\verb|\\0|");
2141 static void TeXUnfilter(wxString
* str
)
2143 // FIXME may be done much more quickly
2148 static wxRegEx
reNonSpecialSpecials("\\\\([#$%&_{}])"),
2149 reAccents("\\\\verb\\|([~^])\\|");
2151 reNonSpecialSpecials
.ReplaceAll(str
, "\\1");
2152 reAccents
.ReplaceAll(str
, "\\1");
2155 static wxString
GetAllComments(const spContext
& ctx
)
2158 const MCommentListT
& commentsList
= ctx
.GetCommentList();
2159 for ( MCommentListT::const_iterator i
= commentsList
.begin();
2160 i
!= commentsList
.end();
2162 wxString comment
= (*i
)->GetText();
2164 // don't take comments like "// ----------" &c
2165 comment
.Trim(false);
2166 if ( !comment
.empty() &&
2167 comment
== wxString(comment
[0u], comment
.length() - 1) + '\n' )
2170 comments
<< comment
;
2176 static const char *GetCurrentTimeFormatted(const char *timeFormat
)
2178 static char s_timeBuffer
[128];
2183 ptmNow
= localtime(&timeNow
);
2185 strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
);
2187 return s_timeBuffer
;
2190 static const wxString
GetVersionString()
2192 wxString version
= "$Revision$";
2193 wxRegEx("^\\$Revision$$").ReplaceFirst(&version
, "\\1");
2199 Revision 1.39 2005/05/30 09:26:42 ABX
2200 More warning and error fixes (work in progress with Tinderbox).
2202 Revision 1.38 2005/05/24 09:06:20 ABX
2203 More fixes and wxWidgets coding standards.
2205 Revision 1.37 2005/05/23 15:22:08 ABX
2206 Initial HelpGen source cleaning.
2208 Revision 1.36 2005/04/07 19:54:58 MW
2209 Workarounds to allow compilation by Sun C++ 5.5
2211 Revision 1.35 2004/12/12 11:03:31 VZ
2212 give an error message if we're built in Unicode mode (in response to bug 1079224)
2214 Revision 1.34 2004/11/23 09:53:31 JS
2215 Changed GPL to wxWindows Licence
2217 Revision 1.33 2004/11/12 03:30:07 RL
2219 Cruft cleanup from MJW, strip the tabs out of sound.cpp
2221 Revision 1.32 2004/11/10 21:02:58 VZ
2222 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)
2224 Revision 1.31 2004/10/05 15:38:29 ABX
2225 Warning fixes found under hardest mode of OpenWatcom. Seems clean in Borland, MinGW and DMC.
2227 Revision 1.30 2004/06/18 19:25:50 ABX
2228 Small step in making HelpGen up to date unicode application.
2230 Revision 1.29 2004/06/17 19:00:22 ABX
2231 Warning fixes. Code cleanup. Whitespaces and tabs removed.
2233 Revision 1.28 2004/05/25 11:19:57 JS
2236 Revision 1.27 2003/10/13 17:21:30 MBN
2239 Revision 1.26 2003/09/29 15:18:35 MBN
2240 (Blind) compilation fix for Sun compiler.
2242 Revision 1.25 2003/09/03 17:39:27 MBN
2245 Revision 1.24 2003/08/13 22:59:37 VZ
2248 Revision 1.23 2003/06/13 17:05:43 VZ
2249 quote '|' inside regexes (fixes dump mode); fixed crash due to strange HelpGenApp code
2251 Revision 1.22 2002/01/21 21:18:50 JS
2252 Now adds 'include file' heading
2254 Revision 1.21 2002/01/04 11:06:09 JS
2255 Fixed missing membersections bug and also bug with functions not being written
2258 Revision 1.20 2002/01/03 14:23:33 JS
2259 Added code to make it not duplicate membersections for overloaded functions
2261 Revision 1.19 2002/01/03 13:34:12 JS
2262 Added FlushAll to CloseClass, otherwise text was only flushed right at the end,
2263 and appeared in one file.
2265 Revision 1.18 2002/01/03 12:02:47 JS
2266 Added main() and corrected VC++ project settings
2268 Revision 1.17 2001/11/30 21:43:35 VZ
2269 now the methods are sorted in the correct order in the generated docs
2271 Revision 1.16 2001/11/28 19:27:33 VZ
2272 HelpGen doesn't work in GUI mode
2274 Revision 1.15 2001/11/22 21:59:58 GD
2275 use "..." instead of <...> for wx headers
2277 Revision 1.14 2001/07/19 13:51:29 VZ
2278 fixes to version string
2280 Revision 1.13 2001/07/19 13:44:57 VZ
2281 1. compilation fixes
2282 2. don't quote special characters inside verbatim environment
2284 Revision 1.12 2000/10/09 13:53:33 juliansmart
2286 Doc corrections; added HelpGen project files
2288 Revision 1.11 2000/07/15 19:50:42 cvsuser
2291 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
2292 don't trasnform output dir name to lower case
2294 Revision 1.10 2000/03/11 10:05:23 VS
2295 now compiles with wxBase
2297 Revision 1.9 2000/01/16 13:25:21 VS
2298 compilation fixes (gcc)
2300 Revision 1.8 1999/09/13 14:29:39 JS
2302 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2303 into src for simplicity; added VC++ 5 project file
2305 Revision 1.7 1999/02/21 22:32:32 VZ
2306 1. more C++ parser fixes - now it almost parses wx/string.h
2307 a) #if/#ifdef/#else (very) limited support
2308 b) param type fix - now indirection chars are correctly handled
2309 c) class/struct/union distinction
2310 d) public/private fixes
2311 e) Dump() function added - very useful for debugging
2313 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2314 by default, and this option switches it on)
2316 Revision 1.6 1999/02/20 23:00:26 VZ
2317 1. new 'diff' mode which seems to work
2318 2. output files are not overwritten in 'dmup' mode
2319 3. fixes for better handling of const functions and operators
2320 ----------------------------
2322 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2323 1. Parser improvements
2324 a) const and virtual methods are parsed correctly (not static yet)
2325 b) "const" which is part of the return type is not swallowed
2327 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2328 "//---------" kind comments discarded now.
2329 ----------------------------
2331 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2333 some tweaks to HelpGen
2334 ----------------------------
2336 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2338 HelpGen starting to compile with VC++
2339 ----------------------------
2341 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2343 supports typedefs, generates "See also:" and adds "virtual " for virtual
2345 ----------------------------
2347 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2349 HelpGen is a prototype of the tool for automatic generation of the .tex files
2350 for wxWidgets documentation from C++ headers
2353 /* vi: set tw=80 et ts=4 sw=4: */