1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Main program file for HelpGen
4 // Author: Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Copyright: (c) 1999 VZ
9 // Licence: wxWindows Licence
10 /////////////////////////////////////////////////////////////////////////////
15 1. wx/string.h confuses C++ parser terribly
16 2. C++ parser doesn't know about virtual functions, nor static ones
17 3. param checking is not done for vararg functions
18 4. type comparison is dumb: it doesn't know that "char *" is the same
19 that "char []" nor that "const char *" is the same as "char const *"
21 TODO (+ means fixed), see also the change log at the end of the file.
23 (i) small fixes in the current version
25 +1. Quote special TeX characters like '&' and '_' (=> derive from wxFile)
27 3. Document global variables
30 6. Include file name/line number in the "diff" messages?
31 +7. Support for vararg functions
33 (ii) plans for version 2
34 1. Use wxTextFile for direct file access to avoid one scan method problems
35 2. Use command line parser class for the options
36 3. support for overloaded functions in diff mode (search for OVER)
38 (iii) plans for version 3
39 1. Merging with existing files
43 // =============================================================================
45 // =============================================================================
47 // -----------------------------------------------------------------------------
49 // -----------------------------------------------------------------------------
52 #include "wx/wxprec.h"
59 #error "HelpGen doesn't build in Unicode mode"
63 #include "wx/string.h"
65 #include "wx/dynarray.h"
73 // C++ parsing classes
80 // -----------------------------------------------------------------------------
82 // -----------------------------------------------------------------------------
84 // return the label for the given function name (i.e. argument of \label)
85 static wxString
MakeLabel(const wxChar
*classname
, const wxChar
*funcname
= NULL
);
87 // return the whole \helpref{arg}{arg_label} string
88 static wxString
MakeHelpref(const wxChar
*argument
);
90 // [un]quote special TeX characters (in place)
91 static void TeXFilter(wxString
* str
);
92 static void TeXUnfilter(wxString
* str
); // also trims spaces
94 // get all comments associated with this context
95 static wxString
GetAllComments(const spContext
& ctx
);
97 // get the string with current time (returns pointer to static buffer)
98 // timeFormat is used for the call of strftime(3)
99 static const char *GetCurrentTimeFormatted(const char *timeFormat
);
101 // get the string containing the program version
102 static const wxString
GetVersionString();
104 // -----------------------------------------------------------------------------
106 // -----------------------------------------------------------------------------
108 // a function documentation entry
109 struct FunctionDocEntry
111 FunctionDocEntry(const wxString
& name_
, const wxString
& text_
)
112 : name(name_
), text(text_
) { }
117 // the function doc text
121 static int Compare(FunctionDocEntry
**pp1
, FunctionDocEntry
**pp2
)
123 // the methods should appear in the following order: ctors, dtor, all
124 // the rest in the alphabetical order
125 bool isCtor1
= (*pp1
)->name
== classname
;
126 bool isCtor2
= (*pp2
)->name
== classname
;
130 // we don't order the ctors because we don't know how to do it
134 // ctor comes before non-ctor
139 // non-ctor must come after ctor
143 wxString dtorname
= wxString(_T("~")) + classname
;
145 // there is only one dtor, so the logic here is simpler
146 if ( (*pp1
)->name
== dtorname
) {
149 else if ( (*pp2
)->name
== dtorname
) {
153 // two normal methods
154 return wxStrcmp((*pp1
)->name
, (*pp2
)->name
);
158 static wxString classname
;
161 wxString
FunctionDocEntry::classname
;
163 WX_DECLARE_OBJARRAY(FunctionDocEntry
, FunctionDocEntries
);
165 #include "wx/arrimpl.cpp"
167 WX_DEFINE_OBJARRAY(FunctionDocEntries
);
169 // add a function which sanitazes the string before writing it to the file and
170 // also capable of delaying output and sorting it before really writing it to
171 // the file (done from FlushAll())
172 class wxTeXFile
: public wxFile
177 // write a string to file verbatim (should only be used for the strings
178 // inside verbatim environment)
179 void WriteVerbatim(const wxString
& s
)
184 // write a string quoting TeX specials in it
185 void WriteTeX(const wxString
& s
)
193 // do write everything to file
196 if ( m_text
.empty() )
199 if ( !Write(m_text
) ) {
200 wxLogError(_T("Failed to output generated documentation."));
211 wxTeXFile(const wxTeXFile
&);
212 wxTeXFile
& operator=(const wxTeXFile
&);
217 // helper class which manages the classes and function names to ignore for
218 // the documentation purposes (used by both HelpGenVisitor and DocManager)
219 class IgnoreNamesHandler
222 IgnoreNamesHandler() : m_ignore(CompareIgnoreListEntries
) { }
223 ~IgnoreNamesHandler() { WX_CLEAR_ARRAY(m_ignore
); }
225 // load file with classes/functions to ignore (add them to the names we
227 bool AddNamesFromFile(const wxString
& filename
);
229 // return true if we ignore this function
230 bool IgnoreMethod(const wxString
& classname
,
231 const wxString
& funcname
) const
233 if ( IgnoreClass(classname
) )
236 IgnoreListEntry
ignore(classname
, funcname
);
238 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
241 // return true if we ignore this class entirely
242 bool IgnoreClass(const wxString
& classname
) const
244 IgnoreListEntry
ignore(classname
, wxEmptyString
);
246 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
250 struct IgnoreListEntry
252 IgnoreListEntry(const wxString
& classname
,
253 const wxString
& funcname
)
254 : m_classname(classname
), m_funcname(funcname
)
258 wxString m_classname
;
259 wxString m_funcname
; // if empty, ignore class entirely
262 static int CompareIgnoreListEntries(IgnoreListEntry
*first
,
263 IgnoreListEntry
*second
);
265 // for efficiency, let's sort it
266 public: // FIXME: macro requires it
267 WX_DEFINE_SORTED_ARRAY(IgnoreListEntry
*, ArrayNamesToIgnore
);
270 ArrayNamesToIgnore m_ignore
;
273 IgnoreNamesHandler(const IgnoreNamesHandler
&);
274 IgnoreNamesHandler
& operator=(const IgnoreNamesHandler
&);
277 // visitor implementation which writes all collected data to a .tex file
278 class HelpGenVisitor
: public spVisitor
282 HelpGenVisitor(const wxString
& directoryOut
, bool overwrite
);
284 virtual void VisitFile( spFile
& fl
);
285 virtual void VisitClass( spClass
& cl
);
286 virtual void VisitEnumeration( spEnumeration
& en
);
287 virtual void VisitTypeDef( spTypeDef
& td
);
288 virtual void VisitPreprocessorLine( spPreprocessorLine
& pd
);
289 virtual void VisitAttribute( spAttribute
& attr
);
290 virtual void VisitOperation( spOperation
& op
);
291 virtual void VisitParameter( spParameter
& param
);
295 // get our `ignore' object
296 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
298 // shut up g++ warning (ain't it stupid?)
299 virtual ~HelpGenVisitor() { }
302 // (re)initialize the state
305 // insert documentation for enums/typedefs coming immediately before the
306 // class declaration into the class documentation
307 void InsertTypedefDocs();
308 void InsertEnumDocs();
310 // write the headers for corresponding sections (only once)
311 void InsertDataStructuresHeader();
312 void InsertMethodsHeader();
314 // terminate the function documentation if it was started
315 void CloseFunction();
317 // write out all function docs when there are no more left in this class
318 // after sorting them in alphabetical order
321 wxString m_directoryOut
, // directory for the output
322 m_fileHeader
; // name of the .h file we parse
323 bool m_overwrite
; // overwrite existing files?
324 wxTeXFile m_file
; // file we're writing to now
327 bool m_inClass
, // true after file successfully opened
328 m_inTypesSection
, // enums & typedefs go there
329 m_inMethodSection
, // functions go here
330 m_isFirstParam
; // first parameter of current function?
332 // non empty while parsing a class
333 wxString m_classname
;
335 // these are only non-empty while parsing a method:
336 wxString m_funcName
, // the function name
337 m_textFunc
; // the function doc text
339 // the array containing the documentation entries for the functions in the
340 // class currently being parsed
341 FunctionDocEntries m_arrayFuncDocs
;
343 // holders for "saved" documentation
344 wxString m_textStoredTypedefs
,
345 m_textStoredFunctionComment
;
347 // for enums we have to use an array as we can't intermix the normal text
348 // and the text inside verbatim environment
349 wxArrayString m_storedEnums
,
352 // headers included by this file
353 wxArrayString m_headers
;
355 // ignore handler: tells us which classes to ignore for doc generation
357 IgnoreNamesHandler m_ignoreNames
;
360 HelpGenVisitor(const HelpGenVisitor
&);
361 HelpGenVisitor
& operator=(const HelpGenVisitor
&);
364 // documentation manager - a class which parses TeX files and remembers the
365 // functions documented in them and can later compare them with all functions
366 // found under ctxTop by C++ parser
370 DocManager(bool checkParamNames
);
373 // returns false on failure
374 bool ParseTeXFile(const wxString
& filename
);
376 // returns false if there were any differences
377 bool DumpDifferences(spContext
*ctxTop
) const;
379 // get our `ignore' object
380 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
386 // returns the length of 'match' if the string 'str' starts with it or 0
388 static size_t TryMatch(const wxChar
*str
, const wxChar
*match
);
390 // skip spaces: returns pointer to first non space character (also
391 // updates the value of m_line)
392 const char *SkipSpaces(const char *p
)
394 while ( isspace(*p
) ) {
402 // skips characters until the next 'c' in '*pp' unless it ends before in
403 // which case false is returned and pp points to '\0', otherwise true is
404 // returned and pp points to 'c'
405 bool SkipUntil(const char **pp
, char c
);
407 // the same as SkipUntil() but only spaces are skipped: on first non space
408 // character different from 'c' the function stops and returns false
409 bool SkipSpaceUntil(const char **pp
, char c
);
411 // extract the string between {} and modify '*pp' to point at the
412 // character immediately after the closing '}'. The returned string is empty
414 wxString
ExtractStringBetweenBraces(const char **pp
);
416 // the current file and line while we're in ParseTeXFile (for error
421 // functions and classes to ignore during diff
422 // -------------------------------------------
424 IgnoreNamesHandler m_ignoreNames
;
426 // information about all functions documented in the TeX file(s)
427 // -------------------------------------------------------------
429 public: // Note: Sun C++ 5.5 requires TypeInfo and ParamInfo to be public
431 // info about a type: for now stored as text string, but must be parsed
432 // further later (to know that "char *" == "char []" - TODO)
436 TypeInfo(const wxString
& type
) : m_type(type
) { }
438 bool operator==(const wxString
& type
) const { return m_type
== type
; }
439 bool operator!=(const wxString
& type
) const { return m_type
!= type
; }
441 const wxString
& GetName() const { return m_type
; }
447 friend class ParamInfo
; // for access to TypeInfo
449 // info abotu a function parameter
453 ParamInfo(const wxString
& type
,
454 const wxString
& name
,
455 const wxString
& value
)
456 : m_type(type
), m_name(name
), m_value(value
)
460 const TypeInfo
& GetType() const { return m_type
; }
461 const wxString
& GetName() const { return m_name
; }
462 const wxString
& GetDefValue() const { return m_value
; }
465 TypeInfo m_type
; // type of parameter
466 wxString m_name
; // name
467 wxString m_value
; // default value
470 public: // FIXME: macro requires it
471 WX_DEFINE_ARRAY_PTR(ParamInfo
*, ArrayParamInfo
);
473 // info about a function
486 MethodInfo(const wxString
& type
,
487 const wxString
& name
,
488 const ArrayParamInfo
& params
)
489 : m_typeRet(type
), m_name(name
), m_params(params
)
494 void SetFlag(MethodFlags flag
) { m_flags
|= flag
; }
496 const TypeInfo
& GetType() const { return m_typeRet
; }
497 const wxString
& GetName() const { return m_name
; }
498 const ParamInfo
& GetParam(size_t n
) const { return *(m_params
[n
]); }
499 size_t GetParamCount() const { return m_params
.GetCount(); }
501 bool HasFlag(MethodFlags flag
) const { return (m_flags
& flag
) != 0; }
503 ~MethodInfo() { WX_CLEAR_ARRAY(m_params
); }
506 TypeInfo m_typeRet
; // return type
508 int m_flags
; // bit mask of the value from the enum above
510 ArrayParamInfo m_params
;
513 WX_DEFINE_ARRAY_PTR(MethodInfo
*, ArrayMethodInfo
);
514 WX_DEFINE_ARRAY_PTR(ArrayMethodInfo
*, ArrayMethodInfos
);
517 // first array contains the names of all classes we found, the second has a
518 // pointer to the array of methods of the given class at the same index as
519 // the class name appears in m_classes
520 wxArrayString m_classes
;
521 ArrayMethodInfos m_methods
;
523 // are we checking parameter names?
524 bool m_checkParamNames
;
527 DocManager(const DocManager
&);
528 DocManager
& operator=(const DocManager
&);
531 // =============================================================================
533 // =============================================================================
535 static char **g_argv
= NULL
;
537 // this function never returns
540 wxString prog
= g_argv
[0];
541 wxString basename
= prog
.AfterLast('/');
544 basename
= prog
.AfterLast('\\');
550 "usage: %s [global options] <mode> [mode options] <files...>\n"
552 " where global options are:\n"
555 " -H give this usage message\n"
556 " -V print the version info\n"
557 " -i file file with classes/function to ignore\n"
559 " where mode is one of: dump, diff\n"
561 " dump means generate .tex files for TeX2RTF converter from specified\n"
562 " headers files, mode options are:\n"
563 " -f overwrite existing files\n"
564 " -o outdir directory for generated files\n"
566 " diff means compare the set of methods documented .tex file with the\n"
567 " methods declared in the header:\n"
568 " %s diff <file.h> <files.tex...>.\n"
569 " mode specific options are:\n"
570 " -p do check parameter names (not done by default)\n"
571 "\n", basename
.c_str(), basename
.c_str());
576 int main(int argc
, char **argv
)
580 wxInitializer initializer
;
583 fprintf(stderr
, "Failed to initialize the wxWidgets library, aborting.");
599 wxArrayString filesH
, filesTeX
;
600 wxString directoryOut
, // directory for 'dmup' output
601 ignoreFile
; // file with classes/functions to ignore
602 bool overwrite
= false, // overwrite existing files during 'dump'?
603 paramNames
= false; // check param names during 'diff'?
605 for ( int current
= 1; current
< argc
; current
++ ) {
606 // all options have one letter
607 if ( argv
[current
][0] == '-' ) {
608 if ( argv
[current
][2] == '\0' ) {
609 switch ( argv
[current
][1] ) {
612 wxLog::GetActiveTarget()->SetVerbose();
617 wxLog::GetActiveTarget()->SetVerbose(false);
627 wxLogMessage("HelpGen version %s\n"
628 "(c) 1999-2001 Vadim Zeitlin\n",
629 GetVersionString().c_str());
634 if ( current
>= argc
) {
635 wxLogError("-i option requires an argument.");
640 ignoreFile
= argv
[current
];
644 if ( mode
!= Mode_Diff
) {
645 wxLogError("-p is only valid with diff.");
654 if ( mode
!= Mode_Dump
) {
655 wxLogError("-f is only valid with dump.");
664 if ( mode
!= Mode_Dump
) {
665 wxLogError("-o is only valid with dump.");
671 if ( current
>= argc
) {
672 wxLogError("-o option requires an argument.");
677 directoryOut
= argv
[current
];
678 if ( !directoryOut
.empty() ) {
679 // terminate with a '/' if it doesn't have it
680 switch ( directoryOut
.Last() ) {
691 //else: it's empty, do nothing
696 wxLogError("unknown option '%s'", argv
[current
]);
701 wxLogError("only one letter options are allowed, not '%s'.",
705 // only get here after a break from switch or from else branch of if
710 if ( mode
== Mode_None
) {
711 if ( strcmp(argv
[current
], "diff") == 0 )
713 else if ( strcmp(argv
[current
], "dump") == 0 )
716 wxLogError("unknown mode '%s'.", argv
[current
]);
722 if ( mode
== Mode_Dump
|| filesH
.IsEmpty() ) {
723 filesH
.Add(argv
[current
]);
726 // 2nd files and further are TeX files in diff mode
727 wxASSERT( mode
== Mode_Diff
);
729 filesTeX
.Add(argv
[current
]);
735 // create a parser object and a visitor derivation
736 CJSourceParser parser
;
737 HelpGenVisitor
visitor(directoryOut
, overwrite
);
738 if ( !ignoreFile
.empty() && mode
== Mode_Dump
)
739 visitor
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
741 spContext
*ctxTop
= NULL
;
743 // parse all header files
744 size_t nFiles
= filesH
.GetCount();
745 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
746 wxString header
= filesH
[n
];
747 ctxTop
= parser
.ParseFile(header
);
749 wxLogWarning("Header file '%s' couldn't be processed.",
752 else if ( mode
== Mode_Dump
) {
753 ((spFile
*)ctxTop
)->m_FileName
= header
;
754 visitor
.VisitAll(*ctxTop
);
760 ctxTop
->Dump(wxEmptyString
);
761 #endif // __WXDEBUG__
764 // parse all TeX files
765 if ( mode
== Mode_Diff
) {
767 wxLogError("Can't complete diff.");
773 DocManager
docman(paramNames
);
775 size_t nFiles
= filesTeX
.GetCount();
776 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
777 wxString file
= filesTeX
[n
];
778 if ( !docman
.ParseTeXFile(file
) ) {
779 wxLogWarning("TeX file '%s' couldn't be processed.",
784 if ( !ignoreFile
.empty() )
785 docman
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
787 docman
.DumpDifferences(ctxTop
);
793 // -----------------------------------------------------------------------------
794 // HelpGenVisitor implementation
795 // -----------------------------------------------------------------------------
797 HelpGenVisitor::HelpGenVisitor(const wxString
& directoryOut
,
799 : m_directoryOut(directoryOut
)
801 m_overwrite
= overwrite
;
806 void HelpGenVisitor::Reset()
810 m_inMethodSection
= false;
815 m_textStoredTypedefs
=
816 m_textStoredFunctionComment
= wxEmptyString
;
818 m_arrayFuncDocs
.Empty();
820 m_storedEnums
.Empty();
821 m_storedEnumsVerb
.Empty();
825 void HelpGenVisitor::InsertTypedefDocs()
827 m_file
.WriteTeX(m_textStoredTypedefs
);
828 m_textStoredTypedefs
.Empty();
831 void HelpGenVisitor::InsertEnumDocs()
833 size_t count
= m_storedEnums
.GetCount();
834 for ( size_t n
= 0; n
< count
; n
++ )
836 m_file
.WriteTeX(m_storedEnums
[n
]);
837 m_file
.WriteVerbatim(m_storedEnumsVerb
[n
] + '\n');
840 m_storedEnums
.Empty();
841 m_storedEnumsVerb
.Empty();
844 void HelpGenVisitor::InsertDataStructuresHeader()
846 if ( !m_inTypesSection
) {
847 m_inTypesSection
= true;
849 m_file
.WriteVerbatim("\\wxheading{Data structures}\n\n");
853 void HelpGenVisitor::InsertMethodsHeader()
855 if ( !m_inMethodSection
) {
856 m_inMethodSection
= true;
858 m_file
.WriteVerbatim( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
862 void HelpGenVisitor::CloseFunction()
864 if ( !m_funcName
.empty() ) {
865 if ( m_isFirstParam
) {
867 m_textFunc
<< "\\void";
870 m_textFunc
<< "}\n\n";
872 if ( !m_textStoredFunctionComment
.empty() ) {
873 m_textFunc
<< m_textStoredFunctionComment
<< '\n';
876 m_arrayFuncDocs
.Add(new FunctionDocEntry(m_funcName
, m_textFunc
));
882 void HelpGenVisitor::CloseClass()
888 size_t count
= m_arrayFuncDocs
.GetCount();
892 FunctionDocEntry::classname
= m_classname
;
894 m_arrayFuncDocs
.Sort(FunctionDocEntry::Compare
);
896 // Now examine each first line and if it's been seen, cut it
897 // off (it's a duplicate \membersection)
898 wxHashTable
membersections(wxKEY_STRING
);
900 for ( n
= 0; n
< count
; n
++ )
902 wxString
section(m_arrayFuncDocs
[n
].text
);
904 // Strip leading whitespace
905 int pos
= section
.Find(_T("\\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
.m_FileName
;
957 wxLogVerbose("%s: started generating docs for classes from file '%s'...",
958 GetCurrentTimeFormatted("%H:%M:%S"), m_fileHeader
.c_str());
961 void HelpGenVisitor::VisitClass( spClass
& cl
)
965 if (m_file
.IsOpened())
971 wxString name
= cl
.GetName();
973 if ( m_ignoreNames
.IgnoreClass(name
) ) {
974 wxLogVerbose("Skipping ignored class '%s'.", name
.c_str());
979 // the file name is built from the class name by removing the leading "wx"
980 // if any and converting it to the lower case
982 if ( name(0, 2) == "wx" ) {
983 filename
<< name
.c_str() + 2;
989 filename
.MakeLower();
991 filename
.Prepend(m_directoryOut
);
993 if ( !m_overwrite
&& wxFile::Exists(filename
) ) {
994 wxLogError("Won't overwrite existing file '%s' - please use '-f'.",
1000 m_inClass
= m_file
.Open(filename
, wxFile::write
);
1002 wxLogError("Can't generate documentation for the class '%s'.",
1009 m_inTypesSection
= false;
1011 wxLogInfo("Created new file '%s' for class '%s'.",
1012 filename
.c_str(), name
.c_str());
1014 // write out the header
1016 header
.Printf("%%\n"
1017 "%% automatically generated by HelpGen %s from\n"
1022 "\\section{\\class{%s}}\\label{%s}\n\n",
1023 GetVersionString().c_str(),
1024 m_fileHeader
.c_str(),
1025 GetCurrentTimeFormatted("%d/%b/%y %H:%M:%S"),
1027 wxString(name
).MakeLower().c_str());
1029 m_file
.WriteVerbatim(header
);
1031 // the entire text we're writing to file
1034 // if the header includes other headers they must be related to it... try to
1035 // automatically generate the "See also" clause
1036 if ( !m_headers
.IsEmpty() ) {
1037 // correspondence between wxWidgets headers and class names
1038 static const char *headers
[] = {
1047 // NULL here means not to insert anything in "See also" for the
1048 // corresponding header
1049 static const char *classes
[] = {
1058 wxASSERT_MSG( WXSIZEOF(headers
) == WXSIZEOF(classes
),
1059 "arrays must be in sync!" );
1061 wxArrayInt interestingClasses
;
1063 size_t count
= m_headers
.Count(), index
;
1064 for ( size_t n
= 0; n
< count
; n
++ ) {
1065 wxString baseHeaderName
= m_headers
[n
].Before('.');
1066 if ( baseHeaderName(0, 3) != "wx/" )
1069 baseHeaderName
.erase(0, 3);
1070 for ( index
= 0; index
< WXSIZEOF(headers
); index
++ ) {
1071 if ( Stricmp(baseHeaderName
, headers
[index
]) == 0 )
1075 if ( (index
< WXSIZEOF(headers
)) && classes
[index
] ) {
1076 // interesting header
1077 interestingClasses
.Add(index
);
1081 if ( !interestingClasses
.IsEmpty() ) {
1082 // do generate "See also" clause
1083 totalText
<< "\\wxheading{See also:}\n\n";
1085 count
= interestingClasses
.Count();
1086 for ( index
= 0; index
< count
; index
++ ) {
1090 totalText
<< MakeHelpref(classes
[interestingClasses
[index
]]);
1093 totalText
<< "\n\n";
1097 // the comment before the class generally explains what is it for so put it
1098 // in place of the class description
1099 if ( cl
.HasComments() ) {
1100 wxString comment
= GetAllComments(cl
);
1102 totalText
<< '\n' << comment
<< '\n';
1105 // derived from section
1106 wxString derived
= "\\wxheading{Derived from}\n\n";
1108 const StrListT
& baseClasses
= cl
.m_SuperClassNames
;
1109 if ( baseClasses
.size() == 0 ) {
1110 derived
<< "No base class";
1114 for ( StrListT::const_iterator i
= baseClasses
.begin();
1115 i
!= baseClasses
.end();
1118 // separate from the previous one
1119 derived
<< "\\\\\n";
1125 wxString baseclass
= *i
;
1126 derived
<< "\\helpref{" << baseclass
<< "}";
1127 derived
<< "{" << baseclass
.MakeLower() << "}";
1130 totalText
<< derived
<< "\n\n";
1132 // include file section
1133 wxString includeFile
= "\\wxheading{Include files}\n\n";
1134 includeFile
<< "<" << m_fileHeader
<< ">";
1136 totalText
<< includeFile
<< "\n\n";
1138 // write all this to file
1139 m_file
.WriteTeX(totalText
);
1141 // if there were any enums/typedefs before, insert their documentation now
1142 InsertDataStructuresHeader();
1143 InsertTypedefDocs();
1149 void HelpGenVisitor::VisitEnumeration( spEnumeration
& en
)
1153 if ( m_inMethodSection
) {
1154 // FIXME that's a bug, but tell the user aboit it nevertheless... we
1155 // should be smart enough to process even the enums which come after the
1157 wxLogWarning("enum '%s' ignored, please put it before the class "
1158 "methods.", en
.GetName().c_str());
1162 // simply copy the enum text in the docs
1163 wxString enumeration
= GetAllComments(en
),
1166 enumerationVerb
<< _T("\\begin{verbatim}\n")
1168 << _T("\n\\end{verbatim}\n");
1170 // remember for later use if we're not inside a class yet
1172 m_storedEnums
.Add(enumeration
);
1173 m_storedEnumsVerb
.Add(enumerationVerb
);
1176 // write the header for this section if not done yet
1177 InsertDataStructuresHeader();
1179 m_file
.WriteTeX(enumeration
);
1180 m_file
.WriteVerbatim(enumerationVerb
);
1181 m_file
.WriteVerbatim('\n');
1185 void HelpGenVisitor::VisitTypeDef( spTypeDef
& td
)
1189 if ( m_inMethodSection
) {
1190 // FIXME that's a bug, but tell the user aboit it nevertheless...
1191 wxLogWarning("typedef '%s' ignored, please put it before the class "
1192 "methods.", td
.GetName().c_str());
1196 wxString typedefdoc
;
1197 typedefdoc
<< _T("{\\small \\begin{verbatim}\n")
1198 << _T("typedef ") << td
.m_OriginalType
<< _T(' ') << td
.GetName()
1199 << _T("\n\\end{verbatim}}\n")
1200 << GetAllComments(td
);
1202 // remember for later use if we're not inside a class yet
1204 if ( !m_textStoredTypedefs
.empty() ) {
1205 m_textStoredTypedefs
<< '\n';
1208 m_textStoredTypedefs
<< typedefdoc
;
1211 // write the header for this section if not done yet
1212 InsertDataStructuresHeader();
1215 m_file
.WriteTeX(typedefdoc
);
1219 void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine
& pd
)
1221 switch ( pd
.GetStatementType() ) {
1222 case SP_PREP_DEF_INCLUDE_FILE
:
1223 m_headers
.Add(pd
.CPP_GetIncludedFileNeme());
1226 case SP_PREP_DEF_DEFINE_SYMBOL
:
1227 // TODO decide if it's a constant and document it if it is
1232 void HelpGenVisitor::VisitAttribute( spAttribute
& attr
)
1236 // only document the public member variables
1237 if ( !m_inClass
|| !attr
.IsPublic() )
1240 wxLogWarning("Ignoring member variable '%s'.", attr
.GetName().c_str());
1243 void HelpGenVisitor::VisitOperation( spOperation
& op
)
1248 // we don't generate docs right now - either we ignore this class
1249 // entirely or we couldn't open the file
1253 if ( !op
.IsInClass() ) {
1254 // TODO document global functions
1255 wxLogWarning("skipped global function '%s'.", op
.GetName().c_str());
1260 if ( op
.mVisibility
== SP_VIS_PRIVATE
) {
1261 // FIXME should we document protected functions?
1265 m_classname
= op
.GetClass().GetName();
1266 wxString funcname
= op
.GetName();
1268 if ( m_ignoreNames
.IgnoreMethod(m_classname
, funcname
) ) {
1269 wxLogVerbose("Skipping ignored '%s::%s'.",
1270 m_classname
.c_str(), funcname
.c_str());
1275 InsertMethodsHeader();
1278 m_funcName
= funcname
;
1279 m_isFirstParam
= true;
1281 m_textStoredFunctionComment
= GetAllComments(op
);
1283 // start function documentation
1286 // check for the special case of dtor
1288 if ( (funcname
[0u] == '~') && (m_classname
== funcname
.c_str() + 1) ) {
1289 dtor
.Printf("\\destruct{%s}", m_classname
.c_str());
1293 m_textFunc
.Printf("\n"
1294 "\\membersection{%s::%s}\\label{%s}\n",
1295 m_classname
.c_str(), funcname
.c_str(),
1296 MakeLabel(m_classname
, funcname
).c_str());
1299 if(op
.mIsConstant
) constStr
= _T("const");
1301 wxString virtualStr
;
1302 if(op
.mIsVirtual
) virtualStr
= _T("virtual ");
1305 func
.Printf(_T("\n")
1306 _T("\\%sfunc{%s%s}{%s}{"),
1309 op
.m_RetType
.c_str(),
1314 void HelpGenVisitor::VisitParameter( spParameter
& param
)
1316 if ( m_funcName
.empty() )
1319 if ( m_isFirstParam
) {
1320 m_isFirstParam
= false;
1326 m_textFunc
<< "\\param{" << param
.m_Type
<< " }{" << param
.GetName();
1327 wxString defvalue
= param
.m_InitVal
;
1328 if ( !defvalue
.empty() ) {
1329 m_textFunc
<< " = " << defvalue
;
1335 // ---------------------------------------------------------------------------
1337 // ---------------------------------------------------------------------------
1339 DocManager::DocManager(bool checkParamNames
)
1341 m_checkParamNames
= checkParamNames
;
1344 size_t DocManager::TryMatch(const char *str
, const char *match
)
1346 size_t lenMatch
= 0;
1347 while ( str
[lenMatch
] == match
[lenMatch
] ) {
1350 if ( match
[lenMatch
] == '\0' )
1357 bool DocManager::SkipUntil(const char **pp
, char c
)
1359 const char *p
= *pp
;
1375 bool DocManager::SkipSpaceUntil(const char **pp
, char c
)
1377 const char *p
= *pp
;
1379 if ( !isspace(*p
) || *p
== '\0' )
1393 wxString
DocManager::ExtractStringBetweenBraces(const char **pp
)
1397 if ( !SkipSpaceUntil(pp
, '{') ) {
1398 wxLogWarning("file %s(%d): '{' expected after '\\param'",
1399 m_filename
.c_str(), (int)m_line
);
1403 const char *startParam
= ++*pp
; // skip '{'
1405 if ( !SkipUntil(pp
, '}') ) {
1406 wxLogWarning("file %s(%d): '}' expected after '\\param'",
1407 m_filename
.c_str(), (int)m_line
);
1410 result
= wxString(startParam
, (*pp
)++ - startParam
);
1417 bool DocManager::ParseTeXFile(const wxString
& filename
)
1419 m_filename
= filename
;
1421 wxFile
file(m_filename
, wxFile::read
);
1422 if ( !file
.IsOpened() )
1425 off_t len
= file
.Length();
1426 if ( len
== wxInvalidOffset
)
1429 char *buf
= new char[len
+ 1];
1432 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1438 // reinit everything
1441 wxLogVerbose("%s: starting to parse doc file '%s'.",
1442 GetCurrentTimeFormatted("%H:%M:%S"), m_filename
.c_str());
1444 // the name of the class from the last "\membersection" command: we assume
1445 // that the following "\func" or "\constfunc" always documents a method of
1446 // this class (and it should always be like that in wxWidgets documentation)
1449 for ( const char *current
= buf
; current
- buf
< len
; current
++ ) {
1450 // FIXME parsing is awfully inefficient
1452 if ( *current
== '%' ) {
1453 // comment, skip until the end of line
1455 SkipUntil(¤t
, '\n');
1460 // all the command we're interested in start with '\\'
1461 while ( *current
!= '\\' && *current
!= '\0' ) {
1462 if ( *current
++ == '\n' )
1466 if ( *current
== '\0' ) {
1467 // no more TeX commands left
1471 current
++; // skip '\\'
1479 } foundCommand
= Nothing
;
1481 size_t lenMatch
= TryMatch(current
, "func");
1483 foundCommand
= Func
;
1486 lenMatch
= TryMatch(current
, "constfunc");
1488 foundCommand
= ConstFunc
;
1490 lenMatch
= TryMatch(current
, "membersection");
1493 foundCommand
= MemberSect
;
1497 if ( foundCommand
== Nothing
)
1500 current
+= lenMatch
;
1502 if ( !SkipSpaceUntil(¤t
, '{') ) {
1503 wxLogWarning("file %s(%d): '{' expected after \\func, "
1504 "\\constfunc or \\membersection.",
1505 m_filename
.c_str(), (int)m_line
);
1512 if ( foundCommand
== MemberSect
) {
1513 // what follows has the form <classname>::<funcname>
1514 const char *startClass
= current
;
1515 if ( !SkipUntil(¤t
, ':') || *(current
+ 1) != ':' ) {
1516 wxLogWarning("file %s(%d): '::' expected after "
1517 "\\membersection.", m_filename
.c_str(), (int)m_line
);
1520 classname
= wxString(startClass
, current
- startClass
);
1521 TeXUnfilter(&classname
);
1527 // extract the return type
1528 const char *startRetType
= current
;
1530 if ( !SkipUntil(¤t
, '}') ) {
1531 wxLogWarning("file %s(%d): '}' expected after return type",
1532 m_filename
.c_str(), (int)m_line
);
1537 wxString returnType
= wxString(startRetType
, current
- startRetType
);
1538 TeXUnfilter(&returnType
);
1541 if ( !SkipSpaceUntil(¤t
, '{') ) {
1542 wxLogWarning("file %s(%d): '{' expected after return type",
1543 m_filename
.c_str(), (int)m_line
);
1549 const char *funcEnd
= current
;
1550 if ( !SkipUntil(&funcEnd
, '}') ) {
1551 wxLogWarning("file %s(%d): '}' expected after function name",
1552 m_filename
.c_str(), (int)m_line
);
1557 wxString funcName
= wxString(current
, funcEnd
- current
);
1558 current
= funcEnd
+ 1;
1560 // trim spaces from both sides
1561 funcName
.Trim(false);
1562 funcName
.Trim(true);
1564 // special cases: '$...$' may be used for LaTeX inline math, remove the
1566 if ( funcName
.Find('$') != wxNOT_FOUND
) {
1568 for ( const char *p
= funcName
.c_str(); *p
!= '\0'; p
++ ) {
1569 if ( *p
!= '$' && !isspace(*p
) )
1576 // \destruct{foo} is really ~foo
1577 if ( funcName
[0u] == '\\' ) {
1578 size_t len
= strlen("\\destruct{");
1579 if ( funcName(0, len
) != "\\destruct{" ) {
1580 wxLogWarning("file %s(%d): \\destruct expected",
1581 m_filename
.c_str(), (int)m_line
);
1586 funcName
.erase(0, len
);
1587 funcName
.Prepend('~');
1589 if ( !SkipSpaceUntil(¤t
, '}') ) {
1590 wxLogWarning("file %s(%d): '}' expected after destructor",
1591 m_filename
.c_str(), (int)m_line
);
1596 funcEnd
++; // there is an extra '}' to count
1599 TeXUnfilter(&funcName
);
1602 current
= funcEnd
+ 1; // skip '}'
1603 if ( !SkipSpaceUntil(¤t
, '{') ||
1604 (current
++, !SkipSpaceUntil(¤t
, '\\')) ) {
1605 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1606 m_filename
.c_str(), (int)m_line
);
1611 wxArrayString paramNames
, paramTypes
, paramValues
;
1613 bool isVararg
= false;
1615 current
++; // skip '\\'
1616 lenMatch
= TryMatch(current
, "void");
1618 lenMatch
= TryMatch(current
, "param");
1619 while ( lenMatch
&& (current
- buf
< len
) ) {
1620 current
+= lenMatch
;
1622 // now come {paramtype}{paramname}
1623 wxString paramType
= ExtractStringBetweenBraces(¤t
);
1624 if ( !paramType
.empty() ) {
1625 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1626 if ( !paramText
.empty() ) {
1627 // the param declaration may contain default value
1628 wxString paramName
= paramText
.BeforeFirst('='),
1629 paramValue
= paramText
.AfterFirst('=');
1631 // sanitize all strings
1632 TeXUnfilter(¶mValue
);
1633 TeXUnfilter(¶mName
);
1634 TeXUnfilter(¶mType
);
1636 paramValues
.Add(paramValue
);
1637 paramNames
.Add(paramName
);
1638 paramTypes
.Add(paramType
);
1643 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1644 if ( paramText
== "..." ) {
1648 wxLogWarning("Parameters of '%s::%s' are in "
1650 classname
.c_str(), funcName
.c_str());
1655 current
= SkipSpaces(current
);
1656 if ( *current
== ',' || *current
== '}' ) {
1657 current
= SkipSpaces(++current
);
1659 lenMatch
= TryMatch(current
, "\\param");
1662 wxLogWarning("file %s(%d): ',' or '}' expected after "
1663 "'\\param'", m_filename
.c_str(), (int)m_line
);
1669 // if we got here there was no '\\void', so must have some params
1670 if ( paramNames
.IsEmpty() ) {
1671 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1672 m_filename
.c_str(), (int)m_line
);
1678 // verbose diagnostic output
1680 size_t param
, paramCount
= paramNames
.GetCount();
1681 for ( param
= 0; param
< paramCount
; param
++ ) {
1686 paramsAll
<< paramTypes
[param
] << ' ' << paramNames
[param
];
1690 if (foundCommand
== ConstFunc
)
1691 constStr
= _T(" const");
1693 wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
1702 // store the info about the just found function
1703 ArrayMethodInfo
*methods
;
1704 int index
= m_classes
.Index(classname
);
1705 if ( index
== wxNOT_FOUND
) {
1706 m_classes
.Add(classname
);
1708 methods
= new ArrayMethodInfo
;
1709 m_methods
.Add(methods
);
1712 methods
= m_methods
[(size_t)index
];
1715 ArrayParamInfo params
;
1716 for ( param
= 0; param
< paramCount
; param
++ ) {
1717 params
.Add(new ParamInfo(paramTypes
[param
],
1719 paramValues
[param
]));
1722 MethodInfo
*method
= new MethodInfo(returnType
, funcName
, params
);
1723 if ( foundCommand
== ConstFunc
)
1724 method
->SetFlag(MethodInfo::Const
);
1726 method
->SetFlag(MethodInfo::Vararg
);
1728 methods
->Add(method
);
1733 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1734 GetCurrentTimeFormatted("%H:%M:%S"), m_filename
.c_str());
1739 bool DocManager::DumpDifferences(spContext
*ctxTop
) const
1741 typedef MMemberListT::const_iterator MemberIndex
;
1743 bool foundDiff
= false;
1745 // flag telling us whether the given class was found at all in the header
1746 size_t nClass
, countClassesInDocs
= m_classes
.GetCount();
1747 bool *classExists
= new bool[countClassesInDocs
];
1748 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1749 classExists
[nClass
] = false;
1752 // ctxTop is normally an spFile
1753 wxASSERT( ctxTop
->GetContextType() == SP_CTX_FILE
);
1755 const MMemberListT
& classes
= ctxTop
->GetMembers();
1756 for ( MemberIndex i
= classes
.begin(); i
!= classes
.end(); i
++ ) {
1757 spContext
*ctx
= *i
;
1758 if ( ctx
->GetContextType() != SP_CTX_CLASS
) {
1759 // TODO process also global functions, macros, ...
1763 spClass
*ctxClass
= (spClass
*)ctx
;
1764 const wxString
& nameClass
= ctxClass
->m_Name
;
1765 int index
= m_classes
.Index(nameClass
);
1766 if ( index
== wxNOT_FOUND
) {
1767 if ( !m_ignoreNames
.IgnoreClass(nameClass
) ) {
1770 wxLogError("Class '%s' is not documented at all.",
1774 // it makes no sense to check for its functions
1778 classExists
[index
] = true;
1781 // array of method descriptions for this class
1782 const ArrayMethodInfo
& methods
= *(m_methods
[index
]);
1783 size_t nMethod
, countMethods
= methods
.GetCount();
1785 // flags telling if we already processed given function
1786 bool *methodExists
= new bool[countMethods
];
1787 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1788 methodExists
[nMethod
] = false;
1791 wxArrayString aOverloadedMethods
;
1793 const MMemberListT
& functions
= ctxClass
->GetMembers();
1794 for ( MemberIndex j
= functions
.begin(); j
!= functions
.end(); j
++ ) {
1796 if ( ctx
->GetContextType() != SP_CTX_OPERATION
)
1799 spOperation
*ctxMethod
= (spOperation
*)ctx
;
1800 const wxString
& nameMethod
= ctxMethod
->m_Name
;
1802 // find all functions with the same name
1803 wxArrayInt aMethodsWithSameName
;
1804 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1805 if ( methods
[nMethod
]->GetName() == nameMethod
)
1806 aMethodsWithSameName
.Add(nMethod
);
1809 if ( aMethodsWithSameName
.IsEmpty() && ctxMethod
->IsPublic() ) {
1810 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1813 wxLogError("'%s::%s' is not documented.",
1815 nameMethod
.c_str());
1818 // don't check params
1821 else if ( aMethodsWithSameName
.GetCount() == 1 ) {
1822 index
= (size_t)aMethodsWithSameName
[0u];
1823 methodExists
[index
] = true;
1825 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1828 if ( !ctxMethod
->IsPublic() ) {
1829 wxLogWarning("'%s::%s' is documented but not public.",
1831 nameMethod
.c_str());
1834 // check that the flags match
1835 const MethodInfo
& method
= *(methods
[index
]);
1837 bool isVirtual
= ctxMethod
->mIsVirtual
;
1838 if ( isVirtual
!= method
.HasFlag(MethodInfo::Virtual
) )
1840 wxString virtualStr
;
1841 if(isVirtual
)virtualStr
= _T("not ");
1843 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1847 virtualStr
.c_str());
1850 bool isConst
= ctxMethod
->mIsConstant
;
1851 if ( isConst
!= method
.HasFlag(MethodInfo::Const
) )
1854 if(isConst
)constStr
= _T("not ");
1856 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1863 // check that the params match
1864 const MMemberListT
& params
= ctxMethod
->GetMembers();
1866 if ( params
.size() != method
.GetParamCount() ) {
1867 wxLogError("Incorrect number of parameters for '%s::%s' "
1868 "in the docs: should be %d instead of %d.",
1871 (int)params
.size(), (int)method
.GetParamCount());
1875 for ( MemberIndex k
= params
.begin();
1880 // what else can a function have?
1881 wxASSERT( ctx
->GetContextType() == SP_CTX_PARAMETER
);
1883 spParameter
*ctxParam
= (spParameter
*)ctx
;
1884 const ParamInfo
& param
= method
.GetParam(nParam
);
1885 if ( m_checkParamNames
&&
1886 (param
.GetName() != ctxParam
->m_Name
.c_str()) ) {
1889 wxLogError("Parameter #%d of '%s::%s' should be "
1890 "'%s' and not '%s'.",
1894 ctxParam
->m_Name
.c_str(),
1895 param
.GetName().c_str());
1900 if ( param
.GetType() != ctxParam
->m_Type
) {
1903 wxLogError("Type of parameter '%s' of '%s::%s' "
1904 "should be '%s' and not '%s'.",
1905 ctxParam
->m_Name
.c_str(),
1908 ctxParam
->m_Type
.c_str(),
1909 param
.GetType().GetName().c_str());
1914 if ( param
.GetDefValue() != ctxParam
->m_InitVal
.c_str() ) {
1915 wxLogWarning("Default value of parameter '%s' of "
1916 "'%s::%s' should be '%s' and not "
1918 ctxParam
->m_Name
.c_str(),
1921 ctxParam
->m_InitVal
.c_str(),
1922 param
.GetDefValue().c_str());
1928 // TODO OVER add real support for overloaded methods
1930 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1933 if ( aOverloadedMethods
.Index(nameMethod
) == wxNOT_FOUND
) {
1934 // mark all methods with this name as existing
1935 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1936 if ( methods
[nMethod
]->GetName() == nameMethod
)
1937 methodExists
[nMethod
] = true;
1940 aOverloadedMethods
.Add(nameMethod
);
1942 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1943 "stupid to find the right match - skipping "
1944 "the param and flags checks.",
1946 nameMethod
.c_str());
1948 //else: warning already given
1952 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1953 if ( !methodExists
[nMethod
] ) {
1954 const wxString
& nameMethod
= methods
[nMethod
]->GetName();
1955 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1958 wxLogError("'%s::%s' is documented but doesn't exist.",
1960 nameMethod
.c_str());
1965 delete [] methodExists
;
1968 // check that all classes we found in the docs really exist
1969 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1970 if ( !classExists
[nClass
] ) {
1973 wxLogError("Class '%s' is documented but doesn't exist.",
1974 m_classes
[nClass
].c_str());
1978 delete [] classExists
;
1983 DocManager::~DocManager()
1985 WX_CLEAR_ARRAY(m_methods
);
1988 // ---------------------------------------------------------------------------
1989 // IgnoreNamesHandler implementation
1990 // ---------------------------------------------------------------------------
1992 int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry
*first
,
1993 IgnoreListEntry
*second
)
1995 // first compare the classes
1996 int rc
= first
->m_classname
.Cmp(second
->m_classname
);
1998 rc
= first
->m_funcname
.Cmp(second
->m_funcname
);
2003 bool IgnoreNamesHandler::AddNamesFromFile(const wxString
& filename
)
2005 wxFile
file(filename
, wxFile::read
);
2006 if ( !file
.IsOpened() )
2009 off_t len
= file
.Length();
2010 if ( len
== wxInvalidOffset
)
2013 char *buf
= new char[len
+ 1];
2016 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
2023 for ( const char *current
= buf
; ; current
++ ) {
2025 // skip DOS line separator
2026 if ( *current
== '\r' )
2030 if ( *current
== '\n' || *current
== '\0' ) {
2031 if ( line
[0u] != '#' ) {
2032 if ( line
.Find(':') != wxNOT_FOUND
) {
2033 wxString classname
= line
.BeforeFirst(':'),
2034 funcname
= line
.AfterLast(':');
2035 m_ignore
.Add(new IgnoreListEntry(classname
, funcname
));
2039 m_ignore
.Add(new IgnoreListEntry(line
, wxEmptyString
));
2044 if ( *current
== '\0' )
2059 // -----------------------------------------------------------------------------
2060 // global function implementation
2061 // -----------------------------------------------------------------------------
2063 static wxString
MakeLabel(const char *classname
, const char *funcname
)
2065 wxString
label(classname
);
2066 if ( funcname
&& funcname
[0] == '\\' ) {
2067 // we may have some special TeX macro - so far only \destruct exists,
2068 // but may be later others will be added
2069 static const char *macros
[] = { "destruct" };
2070 static const char *replacement
[] = { "dtor" };
2073 for ( n
= 0; n
< WXSIZEOF(macros
); n
++ ) {
2074 if ( strncmp(funcname
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) {
2080 if ( n
== WXSIZEOF(macros
) ) {
2081 wxLogWarning("unknown function name '%s' - leaving as is.",
2085 funcname
= replacement
[n
];
2090 // special treatment for operatorXXX() stuff because the C operators
2091 // are not valid in LaTeX labels
2093 if ( wxString(funcname
).StartsWith("operator", &oper
) ) {
2094 label
<< "operator";
2107 for ( n
= 0; n
< WXSIZEOF(operatorNames
); n
++ ) {
2108 if ( oper
== operatorNames
[n
].oper
) {
2109 label
<< operatorNames
[n
].name
;
2115 if ( n
== WXSIZEOF(operatorNames
) ) {
2116 wxLogWarning("unknown operator '%s' - making dummy label.",
2122 else // simply use the func name
2133 static wxString
MakeHelpref(const char *argument
)
2136 helpref
<< "\\helpref{" << argument
<< "}{" << MakeLabel(argument
) << '}';
2141 static void TeXFilter(wxString
* str
)
2143 // TeX special which can be quoted (don't include backslash nor braces as
2145 static wxRegEx
reNonSpecialSpecials("[#$%&_]"),
2149 reNonSpecialSpecials
.ReplaceAll(str
, "\\\\\\0");
2151 // can't quote these ones as they produce accents when preceded by
2152 // backslash, so put them inside verb
2153 reAccents
.ReplaceAll(str
, "\\\\verb|\\0|");
2156 static void TeXUnfilter(wxString
* str
)
2158 // FIXME may be done much more quickly
2163 static wxRegEx
reNonSpecialSpecials("\\\\([#$%&_{}])"),
2164 reAccents("\\\\verb\\|([~^])\\|");
2166 reNonSpecialSpecials
.ReplaceAll(str
, "\\1");
2167 reAccents
.ReplaceAll(str
, "\\1");
2170 static wxString
GetAllComments(const spContext
& ctx
)
2173 const MCommentListT
& commentsList
= ctx
.GetCommentList();
2174 for ( MCommentListT::const_iterator i
= commentsList
.begin();
2175 i
!= commentsList
.end();
2177 wxString comment
= (*i
)->GetText();
2179 // don't take comments like "// ----------" &c
2180 comment
.Trim(false);
2181 if ( !comment
.empty() &&
2182 comment
== wxString(comment
[0u], comment
.length() - 1) + '\n' )
2185 comments
<< comment
;
2191 static const char *GetCurrentTimeFormatted(const char *timeFormat
)
2193 static char s_timeBuffer
[128];
2198 ptmNow
= localtime(&timeNow
);
2200 strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
);
2202 return s_timeBuffer
;
2205 static const wxString
GetVersionString()
2207 wxString version
= "$Revision$";
2208 wxRegEx("^\\$Revision$$").ReplaceFirst(&version
, "\\1");
2214 Revision 1.44 2005/05/31 17:47:45 ABX
2215 More warning and error fixes (work in progress with Tinderbox).
2217 Revision 1.43 2005/05/31 15:42:43 ABX
2218 More warning and error fixes (work in progress with Tinderbox).
2220 Revision 1.42 2005/05/31 15:32:49 ABX
2221 More warning and error fixes (work in progress with Tinderbox).
2223 Revision 1.41 2005/05/30 13:06:15 ABX
2224 More warning and error fixes (work in progress with Tinderbox).
2226 Revision 1.40 2005/05/30 11:49:32 ABX
2227 More warning and error fixes (work in progress with Tinderbox).
2229 Revision 1.39 2005/05/30 09:26:42 ABX
2230 More warning and error fixes (work in progress with Tinderbox).
2232 Revision 1.38 2005/05/24 09:06:20 ABX
2233 More fixes and wxWidgets coding standards.
2235 Revision 1.37 2005/05/23 15:22:08 ABX
2236 Initial HelpGen source cleaning.
2238 Revision 1.36 2005/04/07 19:54:58 MW
2239 Workarounds to allow compilation by Sun C++ 5.5
2241 Revision 1.35 2004/12/12 11:03:31 VZ
2242 give an error message if we're built in Unicode mode (in response to bug 1079224)
2244 Revision 1.34 2004/11/23 09:53:31 JS
2245 Changed GPL to wxWindows Licence
2247 Revision 1.33 2004/11/12 03:30:07 RL
2249 Cruft cleanup from MJW, strip the tabs out of sound.cpp
2251 Revision 1.32 2004/11/10 21:02:58 VZ
2252 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)
2254 Revision 1.31 2004/10/05 15:38:29 ABX
2255 Warning fixes found under hardest mode of OpenWatcom. Seems clean in Borland, MinGW and DMC.
2257 Revision 1.30 2004/06/18 19:25:50 ABX
2258 Small step in making HelpGen up to date unicode application.
2260 Revision 1.29 2004/06/17 19:00:22 ABX
2261 Warning fixes. Code cleanup. Whitespaces and tabs removed.
2263 Revision 1.28 2004/05/25 11:19:57 JS
2266 Revision 1.27 2003/10/13 17:21:30 MBN
2269 Revision 1.26 2003/09/29 15:18:35 MBN
2270 (Blind) compilation fix for Sun compiler.
2272 Revision 1.25 2003/09/03 17:39:27 MBN
2275 Revision 1.24 2003/08/13 22:59:37 VZ
2278 Revision 1.23 2003/06/13 17:05:43 VZ
2279 quote '|' inside regexes (fixes dump mode); fixed crash due to strange HelpGenApp code
2281 Revision 1.22 2002/01/21 21:18:50 JS
2282 Now adds 'include file' heading
2284 Revision 1.21 2002/01/04 11:06:09 JS
2285 Fixed missing membersections bug and also bug with functions not being written
2288 Revision 1.20 2002/01/03 14:23:33 JS
2289 Added code to make it not duplicate membersections for overloaded functions
2291 Revision 1.19 2002/01/03 13:34:12 JS
2292 Added FlushAll to CloseClass, otherwise text was only flushed right at the end,
2293 and appeared in one file.
2295 Revision 1.18 2002/01/03 12:02:47 JS
2296 Added main() and corrected VC++ project settings
2298 Revision 1.17 2001/11/30 21:43:35 VZ
2299 now the methods are sorted in the correct order in the generated docs
2301 Revision 1.16 2001/11/28 19:27:33 VZ
2302 HelpGen doesn't work in GUI mode
2304 Revision 1.15 2001/11/22 21:59:58 GD
2305 use "..." instead of <...> for wx headers
2307 Revision 1.14 2001/07/19 13:51:29 VZ
2308 fixes to version string
2310 Revision 1.13 2001/07/19 13:44:57 VZ
2311 1. compilation fixes
2312 2. don't quote special characters inside verbatim environment
2314 Revision 1.12 2000/10/09 13:53:33 juliansmart
2316 Doc corrections; added HelpGen project files
2318 Revision 1.11 2000/07/15 19:50:42 cvsuser
2321 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
2322 don't trasnform output dir name to lower case
2324 Revision 1.10 2000/03/11 10:05:23 VS
2325 now compiles with wxBase
2327 Revision 1.9 2000/01/16 13:25:21 VS
2328 compilation fixes (gcc)
2330 Revision 1.8 1999/09/13 14:29:39 JS
2332 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2333 into src for simplicity; added VC++ 5 project file
2335 Revision 1.7 1999/02/21 22:32:32 VZ
2336 1. more C++ parser fixes - now it almost parses wx/string.h
2337 a) #if/#ifdef/#else (very) limited support
2338 b) param type fix - now indirection chars are correctly handled
2339 c) class/struct/union distinction
2340 d) public/private fixes
2341 e) Dump() function added - very useful for debugging
2343 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2344 by default, and this option switches it on)
2346 Revision 1.6 1999/02/20 23:00:26 VZ
2347 1. new 'diff' mode which seems to work
2348 2. output files are not overwritten in 'dmup' mode
2349 3. fixes for better handling of const functions and operators
2350 ----------------------------
2352 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2353 1. Parser improvements
2354 a) const and virtual methods are parsed correctly (not static yet)
2355 b) "const" which is part of the return type is not swallowed
2357 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2358 "//---------" kind comments discarded now.
2359 ----------------------------
2361 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2363 some tweaks to HelpGen
2364 ----------------------------
2366 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2368 HelpGen starting to compile with VC++
2369 ----------------------------
2371 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2373 supports typedefs, generates "See also:" and adds "virtual " for virtual
2375 ----------------------------
2377 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2379 HelpGen is a prototype of the tool for automatic generation of the .tex files
2380 for wxWidgets documentation from C++ headers
2383 /* vi: set tw=80 et ts=4 sw=4: */