1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Main program file for HelpGen
4 // Author: Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Copyright: (c) 1999 VZ
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"
55 #include "wx/string.h"
57 #include "wx/dynarray.h"
65 // C++ parsing classes
72 // argh, Windows defines this
77 // -----------------------------------------------------------------------------
79 // -----------------------------------------------------------------------------
81 // return the label for the given function name (i.e. argument of \label)
82 static wxString
MakeLabel(const char *classname
, const char *funcname
= NULL
);
84 // return the whole \helpref{arg}{arg_label} string
85 static wxString
MakeHelpref(const char *argument
);
87 // [un]quote special TeX characters (in place)
88 static void TeXFilter(wxString
* str
);
89 static void TeXUnfilter(wxString
* str
); // also trims spaces
91 // get all comments associated with this context
92 static wxString
GetAllComments(const spContext
& ctx
);
94 // get the string with current time (returns pointer to static buffer)
95 // timeFormat is used for the call of strftime(3)
96 static const char *GetCurrentTime(const char *timeFormat
);
98 // get the string containing the program version
99 static const wxString
GetVersionString();
101 // -----------------------------------------------------------------------------
103 // -----------------------------------------------------------------------------
105 // a function documentation entry
106 struct FunctionDocEntry
108 FunctionDocEntry(const wxString
& name_
, const wxString
& text_
)
109 : name(name_
), text(text_
) { }
114 // the function doc text
118 static int Compare(FunctionDocEntry
**pp1
, FunctionDocEntry
**pp2
)
120 // the methods should appear in the following order: ctors, dtor, all
121 // the rest in the alphabetical order
122 bool isCtor1
= (*pp1
)->name
== classname
;
123 bool isCtor2
= (*pp2
)->name
== classname
;
127 // we don't order the ctors because we don't know how to do it
131 // ctor comes before non-ctor
136 // non-ctor must come after ctor
140 wxString dtorname
= wxString('~') + classname
;
142 // there is only one dtor, so the logic here is simpler
143 if ( (*pp1
)->name
== dtorname
) {
146 else if ( (*pp2
)->name
== dtorname
) {
150 // two normal methods
151 return strcmp((*pp1
)->name
, (*pp2
)->name
);
155 static wxString classname
;
158 wxString
FunctionDocEntry::classname
;
160 WX_DECLARE_OBJARRAY(FunctionDocEntry
, FunctionDocEntries
);
162 #include "wx/arrimpl.cpp"
164 WX_DEFINE_OBJARRAY(FunctionDocEntries
);
166 // add a function which sanitazes the string before writing it to the file and
167 // also capable of delaying output and sorting it before really writing it to
168 // the file (done from FlushAll())
169 class wxTeXFile
: public wxFile
174 // write a string to file verbatim (should only be used for the strings
175 // inside verbatim environment)
176 void WriteVerbatim(const wxString
& s
)
181 // write a string quoting TeX specials in it
182 void WriteTeX(const wxString
& s
)
190 // do write everything to file
193 if ( m_text
.empty() )
196 if ( !Write(m_text
) ) {
197 wxLogError("Failed to output generated documentation.");
208 wxTeXFile(const wxTeXFile
&);
209 wxTeXFile
& operator=(const wxTeXFile
&);
214 // helper class which manages the classes and function names to ignore for
215 // the documentation purposes (used by both HelpGenVisitor and DocManager)
216 class IgnoreNamesHandler
219 IgnoreNamesHandler() : m_ignore(CompareIgnoreListEntries
) { }
220 ~IgnoreNamesHandler() { WX_CLEAR_ARRAY(m_ignore
); }
222 // load file with classes/functions to ignore (add them to the names we
224 bool AddNamesFromFile(const wxString
& filename
);
226 // return TRUE if we ignore this function
227 bool IgnoreMethod(const wxString
& classname
,
228 const wxString
& funcname
) const
230 if ( IgnoreClass(classname
) )
233 IgnoreListEntry
ignore(classname
, funcname
);
235 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
238 // return TRUE if we ignore this class entirely
239 bool IgnoreClass(const wxString
& classname
) const
241 IgnoreListEntry
ignore(classname
, "");
243 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
247 struct IgnoreListEntry
249 IgnoreListEntry(const wxString
& classname
,
250 const wxString
& funcname
)
251 : m_classname(classname
), m_funcname(funcname
)
255 wxString m_classname
;
256 wxString m_funcname
; // if empty, ignore class entirely
259 static int CompareIgnoreListEntries(IgnoreListEntry
*first
,
260 IgnoreListEntry
*second
);
262 // for efficiency, let's sort it
263 WX_DEFINE_SORTED_ARRAY(IgnoreListEntry
*, ArrayNamesToIgnore
);
265 ArrayNamesToIgnore m_ignore
;
268 IgnoreNamesHandler(const IgnoreNamesHandler
&);
269 IgnoreNamesHandler
& operator=(const IgnoreNamesHandler
&);
272 // visitor implementation which writes all collected data to a .tex file
273 class HelpGenVisitor
: public spVisitor
277 HelpGenVisitor(const wxString
& directoryOut
, bool overwrite
);
279 virtual void VisitFile( spFile
& fl
);
280 virtual void VisitClass( spClass
& cl
);
281 virtual void VisitEnumeration( spEnumeration
& en
);
282 virtual void VisitTypeDef( spTypeDef
& td
);
283 virtual void VisitPreprocessorLine( spPreprocessorLine
& pd
);
284 virtual void VisitAttribute( spAttribute
& attr
);
285 virtual void VisitOperation( spOperation
& op
);
286 virtual void VisitParameter( spParameter
& param
);
290 // get our `ignore' object
291 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
293 // shut up g++ warning (ain't it stupid?)
294 virtual ~HelpGenVisitor() { }
297 // (re)initialize the state
300 // insert documentation for enums/typedefs coming immediately before the
301 // class declaration into the class documentation
302 void InsertTypedefDocs();
303 void InsertEnumDocs();
305 // write the headers for corresponding sections (only once)
306 void InsertDataStructuresHeader();
307 void InsertMethodsHeader();
309 // terminate the function documentation if it was started
310 void CloseFunction();
312 // write out all function docs when there are no more left in this class
313 // after sorting them in alphabetical order
316 wxString m_directoryOut
, // directory for the output
317 m_fileHeader
; // name of the .h file we parse
318 bool m_overwrite
; // overwrite existing files?
319 wxTeXFile m_file
; // file we're writing to now
322 bool m_inClass
, // TRUE after file successfully opened
323 m_inTypesSection
, // enums & typedefs go there
324 m_inMethodSection
, // functions go here
325 m_isFirstParam
; // first parameter of current function?
327 // non empty while parsing a class
328 wxString m_classname
;
330 // these are only non-empty while parsing a method:
331 wxString m_funcName
, // the function name
332 m_textFunc
; // the function doc text
334 // the array containing the documentation entries for the functions in the
335 // class currently being parsed
336 FunctionDocEntries m_arrayFuncDocs
;
338 // holders for "saved" documentation
339 wxString m_textStoredTypedefs
,
340 m_textStoredFunctionComment
;
342 // for enums we have to use an array as we can't intermix the normal text
343 // and the text inside verbatim environment
344 wxArrayString m_storedEnums
,
347 // headers included by this file
348 wxArrayString m_headers
;
350 // ignore handler: tells us which classes to ignore for doc generation
352 IgnoreNamesHandler m_ignoreNames
;
355 HelpGenVisitor(const HelpGenVisitor
&);
356 HelpGenVisitor
& operator=(const HelpGenVisitor
&);
359 // documentation manager - a class which parses TeX files and remembers the
360 // functions documented in them and can later compare them with all functions
361 // found under ctxTop by C++ parser
365 DocManager(bool checkParamNames
);
368 // returns FALSE on failure
369 bool ParseTeXFile(const wxString
& filename
);
371 // returns FALSE if there were any differences
372 bool DumpDifferences(spContext
*ctxTop
) const;
374 // get our `ignore' object
375 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
381 // returns the length of 'match' if the string 'str' starts with it or 0
383 static size_t TryMatch(const char *str
, const char *match
);
385 // skip spaces: returns pointer to first non space character (also
386 // updates the value of m_line)
387 const char *SkipSpaces(const char *p
)
389 while ( isspace(*p
) ) {
397 // skips characters until the next 'c' in '*pp' unless it ends before in
398 // which case FALSE is returned and pp points to '\0', otherwise TRUE is
399 // returned and pp points to 'c'
400 bool SkipUntil(const char **pp
, char c
);
402 // the same as SkipUntil() but only spaces are skipped: on first non space
403 // character different from 'c' the function stops and returns FALSE
404 bool SkipSpaceUntil(const char **pp
, char c
);
406 // extract the string between {} and modify '*pp' to point at the
407 // character immediately after the closing '}'. The returned string is empty
409 wxString
ExtractStringBetweenBraces(const char **pp
);
411 // the current file and line while we're in ParseTeXFile (for error
416 // functions and classes to ignore during diff
417 // -------------------------------------------
419 IgnoreNamesHandler m_ignoreNames
;
421 // information about all functions documented in the TeX file(s)
422 // -------------------------------------------------------------
424 // info about a type: for now stored as text string, but must be parsed
425 // further later (to know that "char *" == "char []" - TODO)
429 TypeInfo(const wxString
& type
) : m_type(type
) { }
431 bool operator==(const wxString
& type
) const { return m_type
== type
; }
432 bool operator!=(const wxString
& type
) const { return m_type
!= type
; }
434 const wxString
& GetName() const { return m_type
; }
440 // info abotu a function parameter
444 ParamInfo(const wxString
& type
,
445 const wxString
& name
,
446 const wxString
& value
)
447 : m_type(type
), m_name(name
), m_value(value
)
451 const TypeInfo
& GetType() const { return m_type
; }
452 const wxString
& GetName() const { return m_name
; }
453 const wxString
& GetDefValue() const { return m_value
; }
456 TypeInfo m_type
; // type of parameter
457 wxString m_name
; // name
458 wxString m_value
; // default value
461 WX_DEFINE_ARRAY(ParamInfo
*, ArrayParamInfo
);
463 // info about a function
476 MethodInfo(const wxString
& type
,
477 const wxString
& name
,
478 const ArrayParamInfo
& params
)
479 : m_typeRet(type
), m_name(name
), m_params(params
)
484 void SetFlag(MethodFlags flag
) { m_flags
|= flag
; }
486 const TypeInfo
& GetType() const { return m_typeRet
; }
487 const wxString
& GetName() const { return m_name
; }
488 const ParamInfo
& GetParam(size_t n
) const { return *(m_params
[n
]); }
489 size_t GetParamCount() const { return m_params
.GetCount(); }
491 bool HasFlag(MethodFlags flag
) const { return (m_flags
& flag
) != 0; }
493 ~MethodInfo() { WX_CLEAR_ARRAY(m_params
); }
496 TypeInfo m_typeRet
; // return type
498 int m_flags
; // bit mask of the value from the enum above
500 ArrayParamInfo m_params
;
503 WX_DEFINE_ARRAY(MethodInfo
*, ArrayMethodInfo
);
504 WX_DEFINE_ARRAY(ArrayMethodInfo
*, ArrayMethodInfos
);
506 // first array contains the names of all classes we found, the second has a
507 // pointer to the array of methods of the given class at the same index as
508 // the class name appears in m_classes
509 wxArrayString m_classes
;
510 ArrayMethodInfos m_methods
;
512 // are we checking parameter names?
513 bool m_checkParamNames
;
516 DocManager(const DocManager
&);
517 DocManager
& operator=(const DocManager
&);
520 // =============================================================================
522 // =============================================================================
524 static char **g_argv
= NULL
;
526 // this function never returns
529 wxString prog
= g_argv
[0];
530 wxString basename
= prog
.AfterLast('/');
533 basename
= prog
.AfterLast('\\');
539 "usage: %s [global options] <mode> [mode options] <files...>\n"
541 " where global options are:\n"
544 " -H give this usage message\n"
545 " -V print the version info\n"
546 " -i file file with classes/function to ignore\n"
548 " where mode is one of: dump, diff\n"
550 " dump means generate .tex files for TeX2RTF converter from specified\n"
551 " headers files, mode options are:\n"
552 " -f overwrite existing files\n"
553 " -o outdir directory for generated files\n"
555 " diff means compare the set of methods documented .tex file with the\n"
556 " methods declared in the header:\n"
557 " %s diff <file.h> <files.tex...>.\n"
558 " mode specific options are:\n"
559 " -p do check parameter names (not done by default)\n"
560 "\n", basename
.c_str(), basename
.c_str());
565 int main(int argc
, char **argv
)
569 wxInitializer initializer
;
572 fprintf(stderr
, "Failed to initialize the wxWindows library, aborting.");
588 wxArrayString filesH
, filesTeX
;
589 wxString directoryOut
, // directory for 'dmup' output
590 ignoreFile
; // file with classes/functions to ignore
591 bool overwrite
= FALSE
, // overwrite existing files during 'dump'?
592 paramNames
= FALSE
; // check param names during 'diff'?
594 for ( int current
= 1; current
< argc
; current
++ ) {
595 // all options have one letter
596 if ( argv
[current
][0] == '-' ) {
597 if ( argv
[current
][2] == '\0' ) {
598 switch ( argv
[current
][1] ) {
601 wxLog::GetActiveTarget()->SetVerbose();
606 wxLog::GetActiveTarget()->SetVerbose(FALSE
);
616 wxLogMessage("HelpGen version %s\n"
617 "(c) 1999-2001 Vadim Zeitlin\n",
618 GetVersionString().c_str());
623 if ( current
>= argc
) {
624 wxLogError("-i option requires an argument.");
629 ignoreFile
= argv
[current
];
633 if ( mode
!= Mode_Diff
) {
634 wxLogError("-p is only valid with diff.");
643 if ( mode
!= Mode_Dump
) {
644 wxLogError("-f is only valid with dump.");
653 if ( mode
!= Mode_Dump
) {
654 wxLogError("-o is only valid with dump.");
660 if ( current
>= argc
) {
661 wxLogError("-o option requires an argument.");
666 directoryOut
= argv
[current
];
667 if ( !!directoryOut
) {
668 // terminate with a '/' if it doesn't have it
669 switch ( directoryOut
.Last() ) {
680 //else: it's empty, do nothing
685 wxLogError("unknown option '%s'", argv
[current
]);
690 wxLogError("only one letter options are allowed, not '%s'.",
694 // only get here after a break from switch or from else branch of if
699 if ( mode
== Mode_None
) {
700 if ( strcmp(argv
[current
], "diff") == 0 )
702 else if ( strcmp(argv
[current
], "dump") == 0 )
705 wxLogError("unknown mode '%s'.", argv
[current
]);
711 if ( mode
== Mode_Dump
|| filesH
.IsEmpty() ) {
712 filesH
.Add(argv
[current
]);
715 // 2nd files and further are TeX files in diff mode
716 wxASSERT( mode
== Mode_Diff
);
718 filesTeX
.Add(argv
[current
]);
724 // create a parser object and a visitor derivation
725 CJSourceParser parser
;
726 HelpGenVisitor
visitor(directoryOut
, overwrite
);
727 if ( !!ignoreFile
&& mode
== Mode_Dump
)
728 visitor
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
730 spContext
*ctxTop
= NULL
;
732 // parse all header files
733 size_t nFiles
= filesH
.GetCount();
734 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
735 wxString header
= filesH
[n
];
736 ctxTop
= parser
.ParseFile(header
);
738 wxLogWarning("Header file '%s' couldn't be processed.",
741 else if ( mode
== Mode_Dump
) {
742 ((spFile
*)ctxTop
)->mFileName
= header
;
743 visitor
.VisitAll(*ctxTop
);
750 #endif // __WXDEBUG__
753 // parse all TeX files
754 if ( mode
== Mode_Diff
) {
756 wxLogError("Can't complete diff.");
762 DocManager
docman(paramNames
);
764 size_t nFiles
= filesTeX
.GetCount();
765 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
766 wxString file
= filesTeX
[n
];
767 if ( !docman
.ParseTeXFile(file
) ) {
768 wxLogWarning("TeX file '%s' couldn't be processed.",
774 docman
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
776 docman
.DumpDifferences(ctxTop
);
782 // -----------------------------------------------------------------------------
783 // HelpGenVisitor implementation
784 // -----------------------------------------------------------------------------
786 HelpGenVisitor::HelpGenVisitor(const wxString
& directoryOut
,
788 : m_directoryOut(directoryOut
)
790 m_overwrite
= overwrite
;
795 void HelpGenVisitor::Reset()
799 m_inMethodSection
= FALSE
;
804 m_textStoredTypedefs
=
805 m_textStoredFunctionComment
= "";
807 m_arrayFuncDocs
.Empty();
809 m_storedEnums
.Empty();
810 m_storedEnumsVerb
.Empty();
814 void HelpGenVisitor::InsertTypedefDocs()
816 m_file
.WriteTeX(m_textStoredTypedefs
);
817 m_textStoredTypedefs
.Empty();
820 void HelpGenVisitor::InsertEnumDocs()
822 size_t count
= m_storedEnums
.GetCount();
823 for ( size_t n
= 0; n
< count
; n
++ )
825 m_file
.WriteTeX(m_storedEnums
[n
]);
826 m_file
.WriteVerbatim(m_storedEnumsVerb
[n
] + '\n');
829 m_storedEnums
.Empty();
830 m_storedEnumsVerb
.Empty();
833 void HelpGenVisitor::InsertDataStructuresHeader()
835 if ( !m_inTypesSection
) {
836 m_inTypesSection
= TRUE
;
838 m_file
.WriteVerbatim("\\wxheading{Data structures}\n\n");
842 void HelpGenVisitor::InsertMethodsHeader()
844 if ( !m_inMethodSection
) {
845 m_inMethodSection
= TRUE
;
847 m_file
.WriteVerbatim( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
851 void HelpGenVisitor::CloseFunction()
853 if ( !m_funcName
.empty() ) {
854 if ( m_isFirstParam
) {
856 m_textFunc
<< "\\void";
859 m_textFunc
<< "}\n\n";
861 if ( !m_textStoredFunctionComment
.IsEmpty() ) {
862 m_textFunc
<< m_textStoredFunctionComment
<< '\n';
865 m_arrayFuncDocs
.Add(new FunctionDocEntry(m_funcName
, m_textFunc
));
871 void HelpGenVisitor::CloseClass()
876 size_t count
= m_arrayFuncDocs
.GetCount();
879 FunctionDocEntry::classname
= m_classname
;
881 m_arrayFuncDocs
.Sort(FunctionDocEntry::Compare
);
883 // Now examine each first line and if it's been seen, cut it
884 // off (it's a duplicate \membersection)
885 wxHashTable
membersections(wxKEY_STRING
);
887 for ( n
= 0; n
< count
; n
++ )
889 wxString
section(m_arrayFuncDocs
[n
].text
);
891 // Strip leading whitespace
892 int pos
= section
.Find("\\membersection");
895 section
= section
.Mid(pos
);
898 wxString
ms(section
.BeforeFirst(wxT('\n')));
899 if (membersections
.Get(ms
))
901 m_arrayFuncDocs
[n
].text
= section
.AfterFirst(wxT('\n'));
905 membersections
.Put(ms
, & membersections
);
909 for ( n
= 0; n
< count
; n
++ ) {
910 m_file
.WriteTeX(m_arrayFuncDocs
[n
].text
);
913 m_arrayFuncDocs
.Empty();
922 void HelpGenVisitor::EndVisit()
928 m_fileHeader
.Empty();
931 if (m_file
.IsOpened())
937 wxLogVerbose("%s: finished generating for the current file.",
938 GetCurrentTime("%H:%M:%S"));
941 void HelpGenVisitor::VisitFile( spFile
& file
)
943 m_fileHeader
= file
.mFileName
;
944 wxLogVerbose("%s: started generating docs for classes from file '%s'...",
945 GetCurrentTime("%H:%M:%S"), m_fileHeader
.c_str());
948 void HelpGenVisitor::VisitClass( spClass
& cl
)
952 if (m_file
.IsOpened())
958 wxString name
= cl
.GetName();
960 if ( m_ignoreNames
.IgnoreClass(name
) ) {
961 wxLogVerbose("Skipping ignored class '%s'.", name
.c_str());
966 // the file name is built from the class name by removing the leading "wx"
967 // if any and converting it to the lower case
969 if ( name(0, 2) == "wx" ) {
970 filename
<< name
.c_str() + 2;
976 filename
.MakeLower();
978 filename
.Prepend(m_directoryOut
);
980 if ( !m_overwrite
&& wxFile::Exists(filename
) ) {
981 wxLogError("Won't overwrite existing file '%s' - please use '-f'.",
987 m_inClass
= m_file
.Open(filename
, wxFile::write
);
989 wxLogError("Can't generate documentation for the class '%s'.",
996 m_inTypesSection
= FALSE
;
998 wxLogInfo("Created new file '%s' for class '%s'.",
999 filename
.c_str(), name
.c_str());
1001 // write out the header
1003 header
.Printf("%%\n"
1004 "%% automatically generated by HelpGen %s from\n"
1009 "\\section{\\class{%s}}\\label{%s}\n\n",
1010 GetVersionString().c_str(),
1011 m_fileHeader
.c_str(),
1012 GetCurrentTime("%d/%b/%y %H:%M:%S"),
1014 wxString(name
).MakeLower().c_str());
1016 m_file
.WriteVerbatim(header
);
1018 // the entire text we're writing to file
1021 // if the header includes other headers they must be related to it... try to
1022 // automatically generate the "See also" clause
1023 if ( !m_headers
.IsEmpty() ) {
1024 // correspondence between wxWindows headers and class names
1025 static const char *headers
[] = {
1034 // NULL here means not to insert anything in "See also" for the
1035 // corresponding header
1036 static const char *classes
[] = {
1045 wxASSERT_MSG( WXSIZEOF(headers
) == WXSIZEOF(classes
),
1046 "arrays must be in sync!" );
1048 wxArrayInt interestingClasses
;
1050 size_t count
= m_headers
.Count(), index
;
1051 for ( size_t n
= 0; n
< count
; n
++ ) {
1052 wxString baseHeaderName
= m_headers
[n
].Before('.');
1053 if ( baseHeaderName(0, 3) != "wx/" )
1056 baseHeaderName
.erase(0, 3);
1057 for ( index
= 0; index
< WXSIZEOF(headers
); index
++ ) {
1058 if ( Stricmp(baseHeaderName
, headers
[index
]) == 0 )
1062 if ( (index
< WXSIZEOF(headers
)) && classes
[index
] ) {
1063 // interesting header
1064 interestingClasses
.Add(index
);
1068 if ( !interestingClasses
.IsEmpty() ) {
1069 // do generate "See also" clause
1070 totalText
<< "\\wxheading{See also:}\n\n";
1072 count
= interestingClasses
.Count();
1073 for ( index
= 0; index
< count
; index
++ ) {
1077 totalText
<< MakeHelpref(classes
[interestingClasses
[index
]]);
1080 totalText
<< "\n\n";
1084 // the comment before the class generally explains what is it for so put it
1085 // in place of the class description
1086 if ( cl
.HasComments() ) {
1087 wxString comment
= GetAllComments(cl
);
1089 totalText
<< '\n' << comment
<< '\n';
1092 // derived from section
1093 wxString derived
= "\\wxheading{Derived from}\n\n";
1095 const StrListT
& baseClasses
= cl
.mSuperClassNames
;
1096 if ( baseClasses
.size() == 0 ) {
1097 derived
<< "No base class";
1101 for ( StrListT::const_iterator i
= baseClasses
.begin();
1102 i
!= baseClasses
.end();
1105 // separate from the previous one
1106 derived
<< "\\\\\n";
1112 wxString baseclass
= *i
;
1113 derived
<< "\\helpref{" << baseclass
<< "}";
1114 derived
<< "{" << baseclass
.MakeLower() << "}";
1117 totalText
<< derived
<< "\n\n";
1119 // include file section
1120 wxString includeFile
= "\\wxheading{Include files}\n\n";
1121 includeFile
<< "<" << m_fileHeader
<< ">";
1123 totalText
<< includeFile
<< "\n\n";
1125 // write all this to file
1126 m_file
.WriteTeX(totalText
);
1128 // if there were any enums/typedefs before, insert their documentation now
1129 InsertDataStructuresHeader();
1130 InsertTypedefDocs();
1136 void HelpGenVisitor::VisitEnumeration( spEnumeration
& en
)
1140 if ( m_inMethodSection
) {
1141 // FIXME that's a bug, but tell the user aboit it nevertheless... we
1142 // should be smart enough to process even the enums which come after the
1144 wxLogWarning("enum '%s' ignored, please put it before the class "
1145 "methods.", en
.GetName().c_str());
1149 // simply copy the enum text in the docs
1150 wxString enumeration
= GetAllComments(en
),
1153 enumerationVerb
<< "\\begin{verbatim}\n"
1155 << "\n\\end{verbatim}\n";
1157 // remember for later use if we're not inside a class yet
1159 m_storedEnums
.Add(enumeration
);
1160 m_storedEnumsVerb
.Add(enumerationVerb
);
1163 // write the header for this section if not done yet
1164 InsertDataStructuresHeader();
1166 m_file
.WriteTeX(enumeration
);
1167 m_file
.WriteVerbatim(enumerationVerb
);
1168 m_file
.WriteVerbatim('\n');
1172 void HelpGenVisitor::VisitTypeDef( spTypeDef
& td
)
1176 if ( m_inMethodSection
) {
1177 // FIXME that's a bug, but tell the user aboit it nevertheless...
1178 wxLogWarning("typedef '%s' ignored, please put it before the class "
1179 "methods.", td
.GetName().c_str());
1183 wxString typedefdoc
;
1184 typedefdoc
<< "{\\small \\begin{verbatim}\n"
1185 << "typedef " << td
.mOriginalType
<< ' ' << td
.GetName()
1186 << "\n\\end{verbatim}}\n"
1187 << GetAllComments(td
);
1189 // remember for later use if we're not inside a class yet
1191 if ( !m_textStoredTypedefs
.IsEmpty() ) {
1192 m_textStoredTypedefs
<< '\n';
1195 m_textStoredTypedefs
<< typedefdoc
;
1198 // write the header for this section if not done yet
1199 InsertDataStructuresHeader();
1202 m_file
.WriteTeX(typedefdoc
);
1206 void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine
& pd
)
1208 switch ( pd
.GetStatementType() ) {
1209 case SP_PREP_DEF_INCLUDE_FILE
:
1210 m_headers
.Add(pd
.CPP_GetIncludedFileNeme());
1213 case SP_PREP_DEF_DEFINE_SYMBOL
:
1214 // TODO decide if it's a constant and document it if it is
1219 void HelpGenVisitor::VisitAttribute( spAttribute
& attr
)
1223 // only document the public member variables
1224 if ( !m_inClass
|| !attr
.IsPublic() )
1227 wxLogWarning("Ignoring member variable '%s'.", attr
.GetName().c_str());
1230 void HelpGenVisitor::VisitOperation( spOperation
& op
)
1235 // we don't generate docs right now - either we ignore this class
1236 // entirely or we couldn't open the file
1240 if ( !op
.IsInClass() ) {
1241 // TODO document global functions
1242 wxLogWarning("skipped global function '%s'.", op
.GetName().c_str());
1247 if ( op
.mVisibility
== SP_VIS_PRIVATE
) {
1248 // FIXME should we document protected functions?
1252 m_classname
= op
.GetClass().GetName();
1253 wxString funcname
= op
.GetName();
1255 if ( m_ignoreNames
.IgnoreMethod(m_classname
, funcname
) ) {
1256 wxLogVerbose("Skipping ignored '%s::%s'.",
1257 m_classname
.c_str(), funcname
.c_str());
1262 InsertMethodsHeader();
1265 m_funcName
= funcname
;
1266 m_isFirstParam
= TRUE
;
1268 m_textStoredFunctionComment
= GetAllComments(op
);
1270 // start function documentation
1273 // check for the special case of dtor
1275 if ( (funcname
[0] == '~') && (m_classname
== funcname
.c_str() + 1) ) {
1276 dtor
.Printf("\\destruct{%s}", m_classname
.c_str());
1280 m_textFunc
.Printf("\n"
1281 "\\membersection{%s::%s}\\label{%s}\n",
1282 m_classname
.c_str(), funcname
.c_str(),
1283 MakeLabel(m_classname
, funcname
).c_str());
1287 "\\%sfunc{%s%s}{%s}{",
1288 op
.mIsConstant
? "const" : "",
1289 op
.mIsVirtual
? "virtual " : "",
1290 op
.mRetType
.c_str(),
1295 void HelpGenVisitor::VisitParameter( spParameter
& param
)
1297 if ( m_funcName
.empty() )
1300 if ( m_isFirstParam
) {
1301 m_isFirstParam
= FALSE
;
1307 m_textFunc
<< "\\param{" << param
.mType
<< " }{" << param
.GetName();
1308 wxString defvalue
= param
.mInitVal
;
1309 if ( !defvalue
.IsEmpty() ) {
1310 m_textFunc
<< " = " << defvalue
;
1316 // ---------------------------------------------------------------------------
1318 // ---------------------------------------------------------------------------
1320 DocManager::DocManager(bool checkParamNames
)
1322 m_checkParamNames
= checkParamNames
;
1325 size_t DocManager::TryMatch(const char *str
, const char *match
)
1327 size_t lenMatch
= 0;
1328 while ( str
[lenMatch
] == match
[lenMatch
] ) {
1331 if ( match
[lenMatch
] == '\0' )
1338 bool DocManager::SkipUntil(const char **pp
, char c
)
1340 const char *p
= *pp
;
1356 bool DocManager::SkipSpaceUntil(const char **pp
, char c
)
1358 const char *p
= *pp
;
1360 if ( !isspace(*p
) || *p
== '\0' )
1374 wxString
DocManager::ExtractStringBetweenBraces(const char **pp
)
1378 if ( !SkipSpaceUntil(pp
, '{') ) {
1379 wxLogWarning("file %s(%d): '{' expected after '\\param'",
1380 m_filename
.c_str(), m_line
);
1384 const char *startParam
= ++*pp
; // skip '{'
1386 if ( !SkipUntil(pp
, '}') ) {
1387 wxLogWarning("file %s(%d): '}' expected after '\\param'",
1388 m_filename
.c_str(), m_line
);
1391 result
= wxString(startParam
, (*pp
)++ - startParam
);
1398 bool DocManager::ParseTeXFile(const wxString
& filename
)
1400 m_filename
= filename
;
1402 wxFile
file(m_filename
, wxFile::read
);
1403 if ( !file
.IsOpened() )
1406 off_t len
= file
.Length();
1407 if ( len
== wxInvalidOffset
)
1410 char *buf
= new char[len
+ 1];
1413 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1419 // reinit everything
1422 wxLogVerbose("%s: starting to parse doc file '%s'.",
1423 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1425 // the name of the class from the last "\membersection" command: we assume
1426 // that the following "\func" or "\constfunc" always documents a method of
1427 // this class (and it should always be like that in wxWindows documentation)
1430 for ( const char *current
= buf
; current
- buf
< len
; current
++ ) {
1431 // FIXME parsing is awfully inefficient
1433 if ( *current
== '%' ) {
1434 // comment, skip until the end of line
1436 SkipUntil(¤t
, '\n');
1441 // all the command we're interested in start with '\\'
1442 while ( *current
!= '\\' && *current
!= '\0' ) {
1443 if ( *current
++ == '\n' )
1447 if ( *current
== '\0' ) {
1448 // no more TeX commands left
1452 current
++; // skip '\\'
1460 } foundCommand
= Nothing
;
1462 size_t lenMatch
= TryMatch(current
, "func");
1464 foundCommand
= Func
;
1467 lenMatch
= TryMatch(current
, "constfunc");
1469 foundCommand
= ConstFunc
;
1471 lenMatch
= TryMatch(current
, "membersection");
1474 foundCommand
= MemberSect
;
1478 if ( foundCommand
== Nothing
)
1481 current
+= lenMatch
;
1483 if ( !SkipSpaceUntil(¤t
, '{') ) {
1484 wxLogWarning("file %s(%d): '{' expected after \\func, "
1485 "\\constfunc or \\membersection.",
1486 m_filename
.c_str(), m_line
);
1493 if ( foundCommand
== MemberSect
) {
1494 // what follows has the form <classname>::<funcname>
1495 const char *startClass
= current
;
1496 if ( !SkipUntil(¤t
, ':') || *(current
+ 1) != ':' ) {
1497 wxLogWarning("file %s(%d): '::' expected after "
1498 "\\membersection.", m_filename
.c_str(), m_line
);
1501 classname
= wxString(startClass
, current
- startClass
);
1502 TeXUnfilter(&classname
);
1508 // extract the return type
1509 const char *startRetType
= current
;
1511 if ( !SkipUntil(¤t
, '}') ) {
1512 wxLogWarning("file %s(%d): '}' expected after return type",
1513 m_filename
.c_str(), m_line
);
1518 wxString returnType
= wxString(startRetType
, current
- startRetType
);
1519 TeXUnfilter(&returnType
);
1522 if ( !SkipSpaceUntil(¤t
, '{') ) {
1523 wxLogWarning("file %s(%d): '{' expected after return type",
1524 m_filename
.c_str(), m_line
);
1530 const char *funcEnd
= current
;
1531 if ( !SkipUntil(&funcEnd
, '}') ) {
1532 wxLogWarning("file %s(%d): '}' expected after function name",
1533 m_filename
.c_str(), m_line
);
1538 wxString funcName
= wxString(current
, funcEnd
- current
);
1539 current
= funcEnd
+ 1;
1541 // trim spaces from both sides
1542 funcName
.Trim(FALSE
);
1543 funcName
.Trim(TRUE
);
1545 // special cases: '$...$' may be used for LaTeX inline math, remove the
1547 if ( funcName
.Find('$') != wxNOT_FOUND
) {
1549 for ( const char *p
= funcName
.c_str(); *p
!= '\0'; p
++ ) {
1550 if ( *p
!= '$' && !isspace(*p
) )
1557 // \destruct{foo} is really ~foo
1558 if ( funcName
[0u] == '\\' ) {
1559 size_t len
= strlen("\\destruct{");
1560 if ( funcName(0, len
) != "\\destruct{" ) {
1561 wxLogWarning("file %s(%d): \\destruct expected",
1562 m_filename
.c_str(), m_line
);
1567 funcName
.erase(0, len
);
1568 funcName
.Prepend('~');
1570 if ( !SkipSpaceUntil(¤t
, '}') ) {
1571 wxLogWarning("file %s(%d): '}' expected after destructor",
1572 m_filename
.c_str(), m_line
);
1577 funcEnd
++; // there is an extra '}' to count
1580 TeXUnfilter(&funcName
);
1583 current
= funcEnd
+ 1; // skip '}'
1584 if ( !SkipSpaceUntil(¤t
, '{') ||
1585 (current
++, !SkipSpaceUntil(¤t
, '\\')) ) {
1586 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1587 m_filename
.c_str(), m_line
);
1592 wxArrayString paramNames
, paramTypes
, paramValues
;
1594 bool isVararg
= FALSE
;
1596 current
++; // skip '\\'
1597 lenMatch
= TryMatch(current
, "void");
1599 lenMatch
= TryMatch(current
, "param");
1600 while ( lenMatch
&& (current
- buf
< len
) ) {
1601 current
+= lenMatch
;
1603 // now come {paramtype}{paramname}
1604 wxString paramType
= ExtractStringBetweenBraces(¤t
);
1605 if ( !!paramType
) {
1606 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1607 if ( !!paramText
) {
1608 // the param declaration may contain default value
1609 wxString paramName
= paramText
.BeforeFirst('='),
1610 paramValue
= paramText
.AfterFirst('=');
1612 // sanitize all strings
1613 TeXUnfilter(¶mValue
);
1614 TeXUnfilter(¶mName
);
1615 TeXUnfilter(¶mType
);
1617 paramValues
.Add(paramValue
);
1618 paramNames
.Add(paramName
);
1619 paramTypes
.Add(paramType
);
1624 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1625 if ( paramText
== "..." ) {
1629 wxLogWarning("Parameters of '%s::%s' are in "
1631 classname
.c_str(), funcName
.c_str());
1636 current
= SkipSpaces(current
);
1637 if ( *current
== ',' || *current
== '}' ) {
1638 current
= SkipSpaces(++current
);
1640 lenMatch
= TryMatch(current
, "\\param");
1643 wxLogWarning("file %s(%d): ',' or '}' expected after "
1644 "'\\param'", m_filename
.c_str(), m_line
);
1650 // if we got here there was no '\\void', so must have some params
1651 if ( paramNames
.IsEmpty() ) {
1652 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1653 m_filename
.c_str(), m_line
);
1659 // verbose diagnostic output
1661 size_t param
, paramCount
= paramNames
.GetCount();
1662 for ( param
= 0; param
< paramCount
; param
++ ) {
1667 paramsAll
<< paramTypes
[param
] << ' ' << paramNames
[param
];
1670 wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
1671 m_filename
.c_str(), m_line
,
1676 foundCommand
== ConstFunc
? " const" : "");
1678 // store the info about the just found function
1679 ArrayMethodInfo
*methods
;
1680 int index
= m_classes
.Index(classname
);
1681 if ( index
== wxNOT_FOUND
) {
1682 m_classes
.Add(classname
);
1684 methods
= new ArrayMethodInfo
;
1685 m_methods
.Add(methods
);
1688 methods
= m_methods
[(size_t)index
];
1691 ArrayParamInfo params
;
1692 for ( param
= 0; param
< paramCount
; param
++ ) {
1693 params
.Add(new ParamInfo(paramTypes
[param
],
1695 paramValues
[param
]));
1698 MethodInfo
*method
= new MethodInfo(returnType
, funcName
, params
);
1699 if ( foundCommand
== ConstFunc
)
1700 method
->SetFlag(MethodInfo::Const
);
1702 method
->SetFlag(MethodInfo::Vararg
);
1704 methods
->Add(method
);
1709 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1710 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1715 bool DocManager::DumpDifferences(spContext
*ctxTop
) const
1717 typedef MMemberListT::const_iterator MemberIndex
;
1719 bool foundDiff
= FALSE
;
1721 // flag telling us whether the given class was found at all in the header
1722 size_t nClass
, countClassesInDocs
= m_classes
.GetCount();
1723 bool *classExists
= new bool[countClassesInDocs
];
1724 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1725 classExists
[nClass
] = FALSE
;
1728 // ctxTop is normally an spFile
1729 wxASSERT( ctxTop
->GetContextType() == SP_CTX_FILE
);
1731 const MMemberListT
& classes
= ctxTop
->GetMembers();
1732 for ( MemberIndex i
= classes
.begin(); i
!= classes
.end(); i
++ ) {
1733 spContext
*ctx
= *i
;
1734 if ( ctx
->GetContextType() != SP_CTX_CLASS
) {
1735 // TODO process also global functions, macros, ...
1739 spClass
*ctxClass
= (spClass
*)ctx
;
1740 const wxString
& nameClass
= ctxClass
->mName
;
1741 int index
= m_classes
.Index(nameClass
);
1742 if ( index
== wxNOT_FOUND
) {
1743 if ( !m_ignoreNames
.IgnoreClass(nameClass
) ) {
1746 wxLogError("Class '%s' is not documented at all.",
1750 // it makes no sense to check for its functions
1754 classExists
[index
] = TRUE
;
1757 // array of method descriptions for this class
1758 const ArrayMethodInfo
& methods
= *(m_methods
[index
]);
1759 size_t nMethod
, countMethods
= methods
.GetCount();
1761 // flags telling if we already processed given function
1762 bool *methodExists
= new bool[countMethods
];
1763 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1764 methodExists
[nMethod
] = FALSE
;
1767 wxArrayString aOverloadedMethods
;
1769 const MMemberListT
& functions
= ctxClass
->GetMembers();
1770 for ( MemberIndex j
= functions
.begin(); j
!= functions
.end(); j
++ ) {
1772 if ( ctx
->GetContextType() != SP_CTX_OPERATION
)
1775 spOperation
*ctxMethod
= (spOperation
*)ctx
;
1776 const wxString
& nameMethod
= ctxMethod
->mName
;
1778 // find all functions with the same name
1779 wxArrayInt aMethodsWithSameName
;
1780 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1781 if ( methods
[nMethod
]->GetName() == nameMethod
)
1782 aMethodsWithSameName
.Add(nMethod
);
1785 if ( aMethodsWithSameName
.IsEmpty() && ctxMethod
->IsPublic() ) {
1786 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1789 wxLogError("'%s::%s' is not documented.",
1791 nameMethod
.c_str());
1794 // don't check params
1797 else if ( aMethodsWithSameName
.GetCount() == 1 ) {
1798 index
= (size_t)aMethodsWithSameName
[0u];
1799 methodExists
[index
] = TRUE
;
1801 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1804 if ( !ctxMethod
->IsPublic() ) {
1805 wxLogWarning("'%s::%s' is documented but not public.",
1807 nameMethod
.c_str());
1810 // check that the flags match
1811 const MethodInfo
& method
= *(methods
[index
]);
1813 bool isVirtual
= ctxMethod
->mIsVirtual
;
1814 if ( isVirtual
!= method
.HasFlag(MethodInfo::Virtual
) ) {
1815 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1819 isVirtual
? "not " : "");
1822 bool isConst
= ctxMethod
->mIsConstant
;
1823 if ( isConst
!= method
.HasFlag(MethodInfo::Const
) ) {
1824 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1828 isConst
? "not " : "");
1831 // check that the params match
1832 const MMemberListT
& params
= ctxMethod
->GetMembers();
1834 if ( params
.size() != method
.GetParamCount() ) {
1835 wxLogError("Incorrect number of parameters for '%s::%s' "
1836 "in the docs: should be %d instead of %d.",
1839 params
.size(), method
.GetParamCount());
1843 for ( MemberIndex k
= params
.begin();
1848 // what else can a function have?
1849 wxASSERT( ctx
->GetContextType() == SP_CTX_PARAMETER
);
1851 spParameter
*ctxParam
= (spParameter
*)ctx
;
1852 const ParamInfo
& param
= method
.GetParam(nParam
);
1853 if ( m_checkParamNames
&&
1854 (param
.GetName() != ctxParam
->mName
) ) {
1857 wxLogError("Parameter #%d of '%s::%s' should be "
1858 "'%s' and not '%s'.",
1862 ctxParam
->mName
.c_str(),
1863 param
.GetName().c_str());
1868 if ( param
.GetType() != ctxParam
->mType
) {
1871 wxLogError("Type of parameter '%s' of '%s::%s' "
1872 "should be '%s' and not '%s'.",
1873 ctxParam
->mName
.c_str(),
1876 ctxParam
->mType
.c_str(),
1877 param
.GetType().GetName().c_str());
1882 if ( param
.GetDefValue() != ctxParam
->mInitVal
) {
1883 wxLogWarning("Default value of parameter '%s' of "
1884 "'%s::%s' should be '%s' and not "
1886 ctxParam
->mName
.c_str(),
1889 ctxParam
->mInitVal
.c_str(),
1890 param
.GetDefValue().c_str());
1896 // TODO OVER add real support for overloaded methods
1898 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1901 if ( aOverloadedMethods
.Index(nameMethod
) == wxNOT_FOUND
) {
1902 // mark all methods with this name as existing
1903 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1904 if ( methods
[nMethod
]->GetName() == nameMethod
)
1905 methodExists
[nMethod
] = TRUE
;
1908 aOverloadedMethods
.Add(nameMethod
);
1910 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1911 "stupid to find the right match - skipping "
1912 "the param and flags checks.",
1914 nameMethod
.c_str());
1916 //else: warning already given
1920 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1921 if ( !methodExists
[nMethod
] ) {
1922 const wxString
& nameMethod
= methods
[nMethod
]->GetName();
1923 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1926 wxLogError("'%s::%s' is documented but doesn't exist.",
1928 nameMethod
.c_str());
1933 delete [] methodExists
;
1936 // check that all classes we found in the docs really exist
1937 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1938 if ( !classExists
[nClass
] ) {
1941 wxLogError("Class '%s' is documented but doesn't exist.",
1942 m_classes
[nClass
].c_str());
1946 delete [] classExists
;
1951 DocManager::~DocManager()
1953 WX_CLEAR_ARRAY(m_methods
);
1956 // ---------------------------------------------------------------------------
1957 // IgnoreNamesHandler implementation
1958 // ---------------------------------------------------------------------------
1960 int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry
*first
,
1961 IgnoreListEntry
*second
)
1963 // first compare the classes
1964 int rc
= first
->m_classname
.Cmp(second
->m_classname
);
1966 rc
= first
->m_funcname
.Cmp(second
->m_funcname
);
1971 bool IgnoreNamesHandler::AddNamesFromFile(const wxString
& filename
)
1973 wxFile
file(filename
, wxFile::read
);
1974 if ( !file
.IsOpened() )
1977 off_t len
= file
.Length();
1978 if ( len
== wxInvalidOffset
)
1981 char *buf
= new char[len
+ 1];
1984 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1991 for ( const char *current
= buf
; ; current
++ ) {
1993 // skip DOS line separator
1994 if ( *current
== '\r' )
1998 if ( *current
== '\n' || *current
== '\0' ) {
1999 if ( line
[0u] != '#' ) {
2000 if ( line
.Find(':') != wxNOT_FOUND
) {
2001 wxString classname
= line
.BeforeFirst(':'),
2002 funcname
= line
.AfterLast(':');
2003 m_ignore
.Add(new IgnoreListEntry(classname
, funcname
));
2007 m_ignore
.Add(new IgnoreListEntry(line
, ""));
2012 if ( *current
== '\0' )
2027 // -----------------------------------------------------------------------------
2028 // global function implementation
2029 // -----------------------------------------------------------------------------
2031 static wxString
MakeLabel(const char *classname
, const char *funcname
)
2033 wxString
label(classname
);
2034 if ( funcname
&& funcname
[0] == '\\' ) {
2035 // we may have some special TeX macro - so far only \destruct exists,
2036 // but may be later others will be added
2037 static const char *macros
[] = { "destruct" };
2038 static const char *replacement
[] = { "dtor" };
2041 for ( n
= 0; n
< WXSIZEOF(macros
); n
++ ) {
2042 if ( strncmp(funcname
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) {
2048 if ( n
== WXSIZEOF(macros
) ) {
2049 wxLogWarning("unknown function name '%s' - leaving as is.",
2053 funcname
= replacement
[n
];
2058 // special treatment for operatorXXX() stuff because the C operators
2059 // are not valid in LaTeX labels
2061 if ( wxString(funcname
).StartsWith("operator", &oper
) ) {
2062 label
<< "operator";
2075 for ( n
= 0; n
< WXSIZEOF(operatorNames
); n
++ ) {
2076 if ( oper
== operatorNames
[n
].oper
) {
2077 label
<< operatorNames
[n
].name
;
2083 if ( n
== WXSIZEOF(operatorNames
) ) {
2084 wxLogWarning("unknown operator '%s' - making dummy label.",
2090 else // simply use the func name
2101 static wxString
MakeHelpref(const char *argument
)
2104 helpref
<< "\\helpref{" << argument
<< "}{" << MakeLabel(argument
) << '}';
2109 static void TeXFilter(wxString
* str
)
2111 // TeX special which can be quoted (don't include backslash nor braces as
2113 static wxRegEx
reNonSpecialSpecials("[#$%&_]"),
2117 reNonSpecialSpecials
.ReplaceAll(str
, "\\\\\\0");
2119 // can't quote these ones as they produce accents when preceded by
2120 // backslash, so put them inside verb
2121 reAccents
.ReplaceAll(str
, "\\\\verb|\\0|");
2124 static void TeXUnfilter(wxString
* str
)
2126 // FIXME may be done much more quickly
2131 static wxRegEx
reNonSpecialSpecials("\\\\([#$%&_{}])"),
2132 reAccents("\\\\verb\\|([~^])\\|");
2134 reNonSpecialSpecials
.ReplaceAll(str
, "\\1");
2135 reAccents
.ReplaceAll(str
, "\\1");
2138 static wxString
GetAllComments(const spContext
& ctx
)
2141 const MCommentListT
& commentsList
= ctx
.GetCommentList();
2142 for ( MCommentListT::const_iterator i
= commentsList
.begin();
2143 i
!= commentsList
.end();
2145 wxString comment
= (*i
)->GetText();
2147 // don't take comments like "// ----------" &c
2148 comment
.Trim(FALSE
);
2150 comment
== wxString(comment
[0u], comment
.length() - 1) + '\n' )
2153 comments
<< comment
;
2159 static const char *GetCurrentTime(const char *timeFormat
)
2161 static char s_timeBuffer
[128];
2166 ptmNow
= localtime(&timeNow
);
2168 strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
);
2170 return s_timeBuffer
;
2173 static const wxString
GetVersionString()
2175 wxString version
= "$Revision$";
2176 wxRegEx("^\\$Revision$$").ReplaceFirst(&version
, "\\1");
2182 Revision 1.25 2003/09/03 17:39:27 MBN
2185 Revision 1.24 2003/08/13 22:59:37 VZ
2188 Revision 1.23 2003/06/13 17:05:43 VZ
2189 quote '|' inside regexes (fixes dump mode); fixed crash due to strange HelpGenApp code
2191 Revision 1.22 2002/01/21 21:18:50 JS
2192 Now adds 'include file' heading
2194 Revision 1.21 2002/01/04 11:06:09 JS
2195 Fixed missing membersections bug and also bug with functions not being written
2198 Revision 1.20 2002/01/03 14:23:33 JS
2199 Added code to make it not duplicate membersections for overloaded functions
2201 Revision 1.19 2002/01/03 13:34:12 JS
2202 Added FlushAll to CloseClass, otherwise text was only flushed right at the end,
2203 and appeared in one file.
2205 Revision 1.18 2002/01/03 12:02:47 JS
2206 Added main() and corrected VC++ project settings
2208 Revision 1.17 2001/11/30 21:43:35 VZ
2209 now the methods are sorted in the correct order in the generated docs
2211 Revision 1.16 2001/11/28 19:27:33 VZ
2212 HelpGen doesn't work in GUI mode
2214 Revision 1.15 2001/11/22 21:59:58 GD
2215 use "..." instead of <...> for wx headers
2217 Revision 1.14 2001/07/19 13:51:29 VZ
2218 fixes to version string
2220 Revision 1.13 2001/07/19 13:44:57 VZ
2221 1. compilation fixes
2222 2. don't quote special characters inside verbatim environment
2224 Revision 1.12 2000/10/09 13:53:33 juliansmart
2226 Doc corrections; added HelpGen project files
2228 Revision 1.11 2000/07/15 19:50:42 cvsuser
2231 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
2232 don't trasnform output dir name to lower case
2234 Revision 1.10 2000/03/11 10:05:23 VS
2235 now compiles with wxBase
2237 Revision 1.9 2000/01/16 13:25:21 VS
2238 compilation fixes (gcc)
2240 Revision 1.8 1999/09/13 14:29:39 JS
2242 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2243 into src for simplicity; added VC++ 5 project file
2245 Revision 1.7 1999/02/21 22:32:32 VZ
2246 1. more C++ parser fixes - now it almost parses wx/string.h
2247 a) #if/#ifdef/#else (very) limited support
2248 b) param type fix - now indirection chars are correctly handled
2249 c) class/struct/union distinction
2250 d) public/private fixes
2251 e) Dump() function added - very useful for debugging
2253 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2254 by default, and this option switches it on)
2256 Revision 1.6 1999/02/20 23:00:26 VZ
2257 1. new 'diff' mode which seems to work
2258 2. output files are not overwritten in 'dmup' mode
2259 3. fixes for better handling of const functions and operators
2260 ----------------------------
2262 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2263 1. Parser improvements
2264 a) const and virtual methods are parsed correctly (not static yet)
2265 b) "const" which is part of the return type is not swallowed
2267 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2268 "//---------" kind comments discarded now.
2269 ----------------------------
2271 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2273 some tweaks to HelpGen
2274 ----------------------------
2276 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2278 HelpGen starting to compile with VC++
2279 ----------------------------
2281 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2283 supports typedefs, generates "See also:" and adds "virtual " for virtual
2285 ----------------------------
2287 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2289 HelpGen is a prototype of the tool for automatic generation of the .tex files
2290 for wxWindows documentation from C++ headers
2293 /* vi: set tw=80 et ts=4 sw=4: */