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 public: // FIXME: macro requires it
264 WX_DEFINE_SORTED_ARRAY(IgnoreListEntry
*, ArrayNamesToIgnore
);
267 ArrayNamesToIgnore m_ignore
;
270 IgnoreNamesHandler(const IgnoreNamesHandler
&);
271 IgnoreNamesHandler
& operator=(const IgnoreNamesHandler
&);
274 // visitor implementation which writes all collected data to a .tex file
275 class HelpGenVisitor
: public spVisitor
279 HelpGenVisitor(const wxString
& directoryOut
, bool overwrite
);
281 virtual void VisitFile( spFile
& fl
);
282 virtual void VisitClass( spClass
& cl
);
283 virtual void VisitEnumeration( spEnumeration
& en
);
284 virtual void VisitTypeDef( spTypeDef
& td
);
285 virtual void VisitPreprocessorLine( spPreprocessorLine
& pd
);
286 virtual void VisitAttribute( spAttribute
& attr
);
287 virtual void VisitOperation( spOperation
& op
);
288 virtual void VisitParameter( spParameter
& param
);
292 // get our `ignore' object
293 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
295 // shut up g++ warning (ain't it stupid?)
296 virtual ~HelpGenVisitor() { }
299 // (re)initialize the state
302 // insert documentation for enums/typedefs coming immediately before the
303 // class declaration into the class documentation
304 void InsertTypedefDocs();
305 void InsertEnumDocs();
307 // write the headers for corresponding sections (only once)
308 void InsertDataStructuresHeader();
309 void InsertMethodsHeader();
311 // terminate the function documentation if it was started
312 void CloseFunction();
314 // write out all function docs when there are no more left in this class
315 // after sorting them in alphabetical order
318 wxString m_directoryOut
, // directory for the output
319 m_fileHeader
; // name of the .h file we parse
320 bool m_overwrite
; // overwrite existing files?
321 wxTeXFile m_file
; // file we're writing to now
324 bool m_inClass
, // true after file successfully opened
325 m_inTypesSection
, // enums & typedefs go there
326 m_inMethodSection
, // functions go here
327 m_isFirstParam
; // first parameter of current function?
329 // non empty while parsing a class
330 wxString m_classname
;
332 // these are only non-empty while parsing a method:
333 wxString m_funcName
, // the function name
334 m_textFunc
; // the function doc text
336 // the array containing the documentation entries for the functions in the
337 // class currently being parsed
338 FunctionDocEntries m_arrayFuncDocs
;
340 // holders for "saved" documentation
341 wxString m_textStoredTypedefs
,
342 m_textStoredFunctionComment
;
344 // for enums we have to use an array as we can't intermix the normal text
345 // and the text inside verbatim environment
346 wxArrayString m_storedEnums
,
349 // headers included by this file
350 wxArrayString m_headers
;
352 // ignore handler: tells us which classes to ignore for doc generation
354 IgnoreNamesHandler m_ignoreNames
;
357 HelpGenVisitor(const HelpGenVisitor
&);
358 HelpGenVisitor
& operator=(const HelpGenVisitor
&);
361 // documentation manager - a class which parses TeX files and remembers the
362 // functions documented in them and can later compare them with all functions
363 // found under ctxTop by C++ parser
367 DocManager(bool checkParamNames
);
370 // returns false on failure
371 bool ParseTeXFile(const wxString
& filename
);
373 // returns false if there were any differences
374 bool DumpDifferences(spContext
*ctxTop
) const;
376 // get our `ignore' object
377 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
383 // returns the length of 'match' if the string 'str' starts with it or 0
385 static size_t TryMatch(const char *str
, const char *match
);
387 // skip spaces: returns pointer to first non space character (also
388 // updates the value of m_line)
389 const char *SkipSpaces(const char *p
)
391 while ( isspace(*p
) ) {
399 // skips characters until the next 'c' in '*pp' unless it ends before in
400 // which case false is returned and pp points to '\0', otherwise true is
401 // returned and pp points to 'c'
402 bool SkipUntil(const char **pp
, char c
);
404 // the same as SkipUntil() but only spaces are skipped: on first non space
405 // character different from 'c' the function stops and returns false
406 bool SkipSpaceUntil(const char **pp
, char c
);
408 // extract the string between {} and modify '*pp' to point at the
409 // character immediately after the closing '}'. The returned string is empty
411 wxString
ExtractStringBetweenBraces(const char **pp
);
413 // the current file and line while we're in ParseTeXFile (for error
418 // functions and classes to ignore during diff
419 // -------------------------------------------
421 IgnoreNamesHandler m_ignoreNames
;
423 // information about all functions documented in the TeX file(s)
424 // -------------------------------------------------------------
426 // info about a type: for now stored as text string, but must be parsed
427 // further later (to know that "char *" == "char []" - TODO)
431 TypeInfo(const wxString
& type
) : m_type(type
) { }
433 bool operator==(const wxString
& type
) const { return m_type
== type
; }
434 bool operator!=(const wxString
& type
) const { return m_type
!= type
; }
436 const wxString
& GetName() const { return m_type
; }
442 friend class ParamInfo
; // for access to TypeInfo
444 // info abotu a function parameter
448 ParamInfo(const wxString
& type
,
449 const wxString
& name
,
450 const wxString
& value
)
451 : m_type(type
), m_name(name
), m_value(value
)
455 const TypeInfo
& GetType() const { return m_type
; }
456 const wxString
& GetName() const { return m_name
; }
457 const wxString
& GetDefValue() const { return m_value
; }
460 TypeInfo m_type
; // type of parameter
461 wxString m_name
; // name
462 wxString m_value
; // default value
465 public: // FIXME: macro requires it
466 WX_DEFINE_ARRAY_PTR(ParamInfo
*, ArrayParamInfo
);
468 // info about a function
481 MethodInfo(const wxString
& type
,
482 const wxString
& name
,
483 const ArrayParamInfo
& params
)
484 : m_typeRet(type
), m_name(name
), m_params(params
)
489 void SetFlag(MethodFlags flag
) { m_flags
|= flag
; }
491 const TypeInfo
& GetType() const { return m_typeRet
; }
492 const wxString
& GetName() const { return m_name
; }
493 const ParamInfo
& GetParam(size_t n
) const { return *(m_params
[n
]); }
494 size_t GetParamCount() const { return m_params
.GetCount(); }
496 bool HasFlag(MethodFlags flag
) const { return (m_flags
& flag
) != 0; }
498 ~MethodInfo() { WX_CLEAR_ARRAY(m_params
); }
501 TypeInfo m_typeRet
; // return type
503 int m_flags
; // bit mask of the value from the enum above
505 ArrayParamInfo m_params
;
508 WX_DEFINE_ARRAY_PTR(MethodInfo
*, ArrayMethodInfo
);
509 WX_DEFINE_ARRAY_PTR(ArrayMethodInfo
*, ArrayMethodInfos
);
512 // first array contains the names of all classes we found, the second has a
513 // pointer to the array of methods of the given class at the same index as
514 // the class name appears in m_classes
515 wxArrayString m_classes
;
516 ArrayMethodInfos m_methods
;
518 // are we checking parameter names?
519 bool m_checkParamNames
;
522 DocManager(const DocManager
&);
523 DocManager
& operator=(const DocManager
&);
526 // =============================================================================
528 // =============================================================================
530 static char **g_argv
= NULL
;
532 // this function never returns
535 wxString prog
= g_argv
[0];
536 wxString basename
= prog
.AfterLast('/');
539 basename
= prog
.AfterLast('\\');
545 "usage: %s [global options] <mode> [mode options] <files...>\n"
547 " where global options are:\n"
550 " -H give this usage message\n"
551 " -V print the version info\n"
552 " -i file file with classes/function to ignore\n"
554 " where mode is one of: dump, diff\n"
556 " dump means generate .tex files for TeX2RTF converter from specified\n"
557 " headers files, mode options are:\n"
558 " -f overwrite existing files\n"
559 " -o outdir directory for generated files\n"
561 " diff means compare the set of methods documented .tex file with the\n"
562 " methods declared in the header:\n"
563 " %s diff <file.h> <files.tex...>.\n"
564 " mode specific options are:\n"
565 " -p do check parameter names (not done by default)\n"
566 "\n", basename
.c_str(), basename
.c_str());
571 int main(int argc
, char **argv
)
575 wxInitializer initializer
;
578 fprintf(stderr
, "Failed to initialize the wxWidgets library, aborting.");
594 wxArrayString filesH
, filesTeX
;
595 wxString directoryOut
, // directory for 'dmup' output
596 ignoreFile
; // file with classes/functions to ignore
597 bool overwrite
= false, // overwrite existing files during 'dump'?
598 paramNames
= false; // check param names during 'diff'?
600 for ( int current
= 1; current
< argc
; current
++ ) {
601 // all options have one letter
602 if ( argv
[current
][0] == '-' ) {
603 if ( argv
[current
][2] == '\0' ) {
604 switch ( argv
[current
][1] ) {
607 wxLog::GetActiveTarget()->SetVerbose();
612 wxLog::GetActiveTarget()->SetVerbose(false);
622 wxLogMessage("HelpGen version %s\n"
623 "(c) 1999-2001 Vadim Zeitlin\n",
624 GetVersionString().c_str());
629 if ( current
>= argc
) {
630 wxLogError("-i option requires an argument.");
635 ignoreFile
= argv
[current
];
639 if ( mode
!= Mode_Diff
) {
640 wxLogError("-p is only valid with diff.");
649 if ( mode
!= Mode_Dump
) {
650 wxLogError("-f is only valid with dump.");
659 if ( mode
!= Mode_Dump
) {
660 wxLogError("-o is only valid with dump.");
666 if ( current
>= argc
) {
667 wxLogError("-o option requires an argument.");
672 directoryOut
= argv
[current
];
673 if ( !!directoryOut
) {
674 // terminate with a '/' if it doesn't have it
675 switch ( directoryOut
.Last() ) {
686 //else: it's empty, do nothing
691 wxLogError("unknown option '%s'", argv
[current
]);
696 wxLogError("only one letter options are allowed, not '%s'.",
700 // only get here after a break from switch or from else branch of if
705 if ( mode
== Mode_None
) {
706 if ( strcmp(argv
[current
], "diff") == 0 )
708 else if ( strcmp(argv
[current
], "dump") == 0 )
711 wxLogError("unknown mode '%s'.", argv
[current
]);
717 if ( mode
== Mode_Dump
|| filesH
.IsEmpty() ) {
718 filesH
.Add(argv
[current
]);
721 // 2nd files and further are TeX files in diff mode
722 wxASSERT( mode
== Mode_Diff
);
724 filesTeX
.Add(argv
[current
]);
730 // create a parser object and a visitor derivation
731 CJSourceParser parser
;
732 HelpGenVisitor
visitor(directoryOut
, overwrite
);
733 if ( !!ignoreFile
&& mode
== Mode_Dump
)
734 visitor
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
736 spContext
*ctxTop
= NULL
;
738 // parse all header files
739 size_t nFiles
= filesH
.GetCount();
740 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
741 wxString header
= filesH
[n
];
742 ctxTop
= parser
.ParseFile(header
);
744 wxLogWarning("Header file '%s' couldn't be processed.",
747 else if ( mode
== Mode_Dump
) {
748 ((spFile
*)ctxTop
)->mFileName
= header
;
749 visitor
.VisitAll(*ctxTop
);
756 #endif // __WXDEBUG__
759 // parse all TeX files
760 if ( mode
== Mode_Diff
) {
762 wxLogError("Can't complete diff.");
768 DocManager
docman(paramNames
);
770 size_t nFiles
= filesTeX
.GetCount();
771 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
772 wxString file
= filesTeX
[n
];
773 if ( !docman
.ParseTeXFile(file
) ) {
774 wxLogWarning("TeX file '%s' couldn't be processed.",
780 docman
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
782 docman
.DumpDifferences(ctxTop
);
788 // -----------------------------------------------------------------------------
789 // HelpGenVisitor implementation
790 // -----------------------------------------------------------------------------
792 HelpGenVisitor::HelpGenVisitor(const wxString
& directoryOut
,
794 : m_directoryOut(directoryOut
)
796 m_overwrite
= overwrite
;
801 void HelpGenVisitor::Reset()
805 m_inMethodSection
= false;
810 m_textStoredTypedefs
=
811 m_textStoredFunctionComment
= "";
813 m_arrayFuncDocs
.Empty();
815 m_storedEnums
.Empty();
816 m_storedEnumsVerb
.Empty();
820 void HelpGenVisitor::InsertTypedefDocs()
822 m_file
.WriteTeX(m_textStoredTypedefs
);
823 m_textStoredTypedefs
.Empty();
826 void HelpGenVisitor::InsertEnumDocs()
828 size_t count
= m_storedEnums
.GetCount();
829 for ( size_t n
= 0; n
< count
; n
++ )
831 m_file
.WriteTeX(m_storedEnums
[n
]);
832 m_file
.WriteVerbatim(m_storedEnumsVerb
[n
] + '\n');
835 m_storedEnums
.Empty();
836 m_storedEnumsVerb
.Empty();
839 void HelpGenVisitor::InsertDataStructuresHeader()
841 if ( !m_inTypesSection
) {
842 m_inTypesSection
= true;
844 m_file
.WriteVerbatim("\\wxheading{Data structures}\n\n");
848 void HelpGenVisitor::InsertMethodsHeader()
850 if ( !m_inMethodSection
) {
851 m_inMethodSection
= true;
853 m_file
.WriteVerbatim( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
857 void HelpGenVisitor::CloseFunction()
859 if ( !m_funcName
.empty() ) {
860 if ( m_isFirstParam
) {
862 m_textFunc
<< "\\void";
865 m_textFunc
<< "}\n\n";
867 if ( !m_textStoredFunctionComment
.IsEmpty() ) {
868 m_textFunc
<< m_textStoredFunctionComment
<< '\n';
871 m_arrayFuncDocs
.Add(new FunctionDocEntry(m_funcName
, m_textFunc
));
877 void HelpGenVisitor::CloseClass()
883 size_t count
= m_arrayFuncDocs
.GetCount();
887 FunctionDocEntry::classname
= m_classname
;
889 m_arrayFuncDocs
.Sort(FunctionDocEntry::Compare
);
891 // Now examine each first line and if it's been seen, cut it
892 // off (it's a duplicate \membersection)
893 wxHashTable
membersections(wxKEY_STRING
);
895 for ( n
= 0; n
< count
; n
++ )
897 wxString
section(m_arrayFuncDocs
[n
].text
);
899 // Strip leading whitespace
900 int pos
= section
.Find("\\membersection");
903 section
= section
.Mid(pos
);
906 wxString
ms(section
.BeforeFirst(wxT('\n')));
907 if (membersections
.Get(ms
))
909 m_arrayFuncDocs
[n
].text
= section
.AfterFirst(wxT('\n'));
913 membersections
.Put(ms
, & membersections
);
917 for ( n
= 0; n
< count
; n
++ ) {
918 m_file
.WriteTeX(m_arrayFuncDocs
[n
].text
);
921 m_arrayFuncDocs
.Empty();
930 void HelpGenVisitor::EndVisit()
936 m_fileHeader
.Empty();
939 if (m_file
.IsOpened())
945 wxLogVerbose("%s: finished generating for the current file.",
946 GetCurrentTime("%H:%M:%S"));
949 void HelpGenVisitor::VisitFile( spFile
& file
)
951 m_fileHeader
= file
.mFileName
;
952 wxLogVerbose("%s: started generating docs for classes from file '%s'...",
953 GetCurrentTime("%H:%M:%S"), m_fileHeader
.c_str());
956 void HelpGenVisitor::VisitClass( spClass
& cl
)
960 if (m_file
.IsOpened())
966 wxString name
= cl
.GetName();
968 if ( m_ignoreNames
.IgnoreClass(name
) ) {
969 wxLogVerbose("Skipping ignored class '%s'.", name
.c_str());
974 // the file name is built from the class name by removing the leading "wx"
975 // if any and converting it to the lower case
977 if ( name(0, 2) == "wx" ) {
978 filename
<< name
.c_str() + 2;
984 filename
.MakeLower();
986 filename
.Prepend(m_directoryOut
);
988 if ( !m_overwrite
&& wxFile::Exists(filename
) ) {
989 wxLogError("Won't overwrite existing file '%s' - please use '-f'.",
995 m_inClass
= m_file
.Open(filename
, wxFile::write
);
997 wxLogError("Can't generate documentation for the class '%s'.",
1004 m_inTypesSection
= false;
1006 wxLogInfo("Created new file '%s' for class '%s'.",
1007 filename
.c_str(), name
.c_str());
1009 // write out the header
1011 header
.Printf("%%\n"
1012 "%% automatically generated by HelpGen %s from\n"
1017 "\\section{\\class{%s}}\\label{%s}\n\n",
1018 GetVersionString().c_str(),
1019 m_fileHeader
.c_str(),
1020 GetCurrentTime("%d/%b/%y %H:%M:%S"),
1022 wxString(name
).MakeLower().c_str());
1024 m_file
.WriteVerbatim(header
);
1026 // the entire text we're writing to file
1029 // if the header includes other headers they must be related to it... try to
1030 // automatically generate the "See also" clause
1031 if ( !m_headers
.IsEmpty() ) {
1032 // correspondence between wxWidgets headers and class names
1033 static const char *headers
[] = {
1042 // NULL here means not to insert anything in "See also" for the
1043 // corresponding header
1044 static const char *classes
[] = {
1053 wxASSERT_MSG( WXSIZEOF(headers
) == WXSIZEOF(classes
),
1054 "arrays must be in sync!" );
1056 wxArrayInt interestingClasses
;
1058 size_t count
= m_headers
.Count(), index
;
1059 for ( size_t n
= 0; n
< count
; n
++ ) {
1060 wxString baseHeaderName
= m_headers
[n
].Before('.');
1061 if ( baseHeaderName(0, 3) != "wx/" )
1064 baseHeaderName
.erase(0, 3);
1065 for ( index
= 0; index
< WXSIZEOF(headers
); index
++ ) {
1066 if ( Stricmp(baseHeaderName
, headers
[index
]) == 0 )
1070 if ( (index
< WXSIZEOF(headers
)) && classes
[index
] ) {
1071 // interesting header
1072 interestingClasses
.Add(index
);
1076 if ( !interestingClasses
.IsEmpty() ) {
1077 // do generate "See also" clause
1078 totalText
<< "\\wxheading{See also:}\n\n";
1080 count
= interestingClasses
.Count();
1081 for ( index
= 0; index
< count
; index
++ ) {
1085 totalText
<< MakeHelpref(classes
[interestingClasses
[index
]]);
1088 totalText
<< "\n\n";
1092 // the comment before the class generally explains what is it for so put it
1093 // in place of the class description
1094 if ( cl
.HasComments() ) {
1095 wxString comment
= GetAllComments(cl
);
1097 totalText
<< '\n' << comment
<< '\n';
1100 // derived from section
1101 wxString derived
= "\\wxheading{Derived from}\n\n";
1103 const StrListT
& baseClasses
= cl
.mSuperClassNames
;
1104 if ( baseClasses
.size() == 0 ) {
1105 derived
<< "No base class";
1109 for ( StrListT::const_iterator i
= baseClasses
.begin();
1110 i
!= baseClasses
.end();
1113 // separate from the previous one
1114 derived
<< "\\\\\n";
1120 wxString baseclass
= *i
;
1121 derived
<< "\\helpref{" << baseclass
<< "}";
1122 derived
<< "{" << baseclass
.MakeLower() << "}";
1125 totalText
<< derived
<< "\n\n";
1127 // include file section
1128 wxString includeFile
= "\\wxheading{Include files}\n\n";
1129 includeFile
<< "<" << m_fileHeader
<< ">";
1131 totalText
<< includeFile
<< "\n\n";
1133 // write all this to file
1134 m_file
.WriteTeX(totalText
);
1136 // if there were any enums/typedefs before, insert their documentation now
1137 InsertDataStructuresHeader();
1138 InsertTypedefDocs();
1144 void HelpGenVisitor::VisitEnumeration( spEnumeration
& en
)
1148 if ( m_inMethodSection
) {
1149 // FIXME that's a bug, but tell the user aboit it nevertheless... we
1150 // should be smart enough to process even the enums which come after the
1152 wxLogWarning("enum '%s' ignored, please put it before the class "
1153 "methods.", en
.GetName().c_str());
1157 // simply copy the enum text in the docs
1158 wxString enumeration
= GetAllComments(en
),
1161 enumerationVerb
<< "\\begin{verbatim}\n"
1163 << "\n\\end{verbatim}\n";
1165 // remember for later use if we're not inside a class yet
1167 m_storedEnums
.Add(enumeration
);
1168 m_storedEnumsVerb
.Add(enumerationVerb
);
1171 // write the header for this section if not done yet
1172 InsertDataStructuresHeader();
1174 m_file
.WriteTeX(enumeration
);
1175 m_file
.WriteVerbatim(enumerationVerb
);
1176 m_file
.WriteVerbatim('\n');
1180 void HelpGenVisitor::VisitTypeDef( spTypeDef
& td
)
1184 if ( m_inMethodSection
) {
1185 // FIXME that's a bug, but tell the user aboit it nevertheless...
1186 wxLogWarning("typedef '%s' ignored, please put it before the class "
1187 "methods.", td
.GetName().c_str());
1191 wxString typedefdoc
;
1192 typedefdoc
<< "{\\small \\begin{verbatim}\n"
1193 << "typedef " << td
.mOriginalType
<< ' ' << td
.GetName()
1194 << "\n\\end{verbatim}}\n"
1195 << GetAllComments(td
);
1197 // remember for later use if we're not inside a class yet
1199 if ( !m_textStoredTypedefs
.IsEmpty() ) {
1200 m_textStoredTypedefs
<< '\n';
1203 m_textStoredTypedefs
<< typedefdoc
;
1206 // write the header for this section if not done yet
1207 InsertDataStructuresHeader();
1210 m_file
.WriteTeX(typedefdoc
);
1214 void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine
& pd
)
1216 switch ( pd
.GetStatementType() ) {
1217 case SP_PREP_DEF_INCLUDE_FILE
:
1218 m_headers
.Add(pd
.CPP_GetIncludedFileNeme());
1221 case SP_PREP_DEF_DEFINE_SYMBOL
:
1222 // TODO decide if it's a constant and document it if it is
1227 void HelpGenVisitor::VisitAttribute( spAttribute
& attr
)
1231 // only document the public member variables
1232 if ( !m_inClass
|| !attr
.IsPublic() )
1235 wxLogWarning("Ignoring member variable '%s'.", attr
.GetName().c_str());
1238 void HelpGenVisitor::VisitOperation( spOperation
& op
)
1243 // we don't generate docs right now - either we ignore this class
1244 // entirely or we couldn't open the file
1248 if ( !op
.IsInClass() ) {
1249 // TODO document global functions
1250 wxLogWarning("skipped global function '%s'.", op
.GetName().c_str());
1255 if ( op
.mVisibility
== SP_VIS_PRIVATE
) {
1256 // FIXME should we document protected functions?
1260 m_classname
= op
.GetClass().GetName();
1261 wxString funcname
= op
.GetName();
1263 if ( m_ignoreNames
.IgnoreMethod(m_classname
, funcname
) ) {
1264 wxLogVerbose("Skipping ignored '%s::%s'.",
1265 m_classname
.c_str(), funcname
.c_str());
1270 InsertMethodsHeader();
1273 m_funcName
= funcname
;
1274 m_isFirstParam
= true;
1276 m_textStoredFunctionComment
= GetAllComments(op
);
1278 // start function documentation
1281 // check for the special case of dtor
1283 if ( (funcname
[0u] == '~') && (m_classname
== funcname
.c_str() + 1) ) {
1284 dtor
.Printf("\\destruct{%s}", m_classname
.c_str());
1288 m_textFunc
.Printf("\n"
1289 "\\membersection{%s::%s}\\label{%s}\n",
1290 m_classname
.c_str(), funcname
.c_str(),
1291 MakeLabel(m_classname
, funcname
).c_str());
1295 "\\%sfunc{%s%s}{%s}{",
1296 op
.mIsConstant
? "const" : "",
1297 op
.mIsVirtual
? "virtual " : "",
1298 op
.mRetType
.c_str(),
1303 void HelpGenVisitor::VisitParameter( spParameter
& param
)
1305 if ( m_funcName
.empty() )
1308 if ( m_isFirstParam
) {
1309 m_isFirstParam
= false;
1315 m_textFunc
<< "\\param{" << param
.mType
<< " }{" << param
.GetName();
1316 wxString defvalue
= param
.mInitVal
;
1317 if ( !defvalue
.IsEmpty() ) {
1318 m_textFunc
<< " = " << defvalue
;
1324 // ---------------------------------------------------------------------------
1326 // ---------------------------------------------------------------------------
1328 DocManager::DocManager(bool checkParamNames
)
1330 m_checkParamNames
= checkParamNames
;
1333 size_t DocManager::TryMatch(const char *str
, const char *match
)
1335 size_t lenMatch
= 0;
1336 while ( str
[lenMatch
] == match
[lenMatch
] ) {
1339 if ( match
[lenMatch
] == '\0' )
1346 bool DocManager::SkipUntil(const char **pp
, char c
)
1348 const char *p
= *pp
;
1364 bool DocManager::SkipSpaceUntil(const char **pp
, char c
)
1366 const char *p
= *pp
;
1368 if ( !isspace(*p
) || *p
== '\0' )
1382 wxString
DocManager::ExtractStringBetweenBraces(const char **pp
)
1386 if ( !SkipSpaceUntil(pp
, '{') ) {
1387 wxLogWarning("file %s(%d): '{' expected after '\\param'",
1388 m_filename
.c_str(), m_line
);
1392 const char *startParam
= ++*pp
; // skip '{'
1394 if ( !SkipUntil(pp
, '}') ) {
1395 wxLogWarning("file %s(%d): '}' expected after '\\param'",
1396 m_filename
.c_str(), m_line
);
1399 result
= wxString(startParam
, (*pp
)++ - startParam
);
1406 bool DocManager::ParseTeXFile(const wxString
& filename
)
1408 m_filename
= filename
;
1410 wxFile
file(m_filename
, wxFile::read
);
1411 if ( !file
.IsOpened() )
1414 off_t len
= file
.Length();
1415 if ( len
== wxInvalidOffset
)
1418 char *buf
= new char[len
+ 1];
1421 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1427 // reinit everything
1430 wxLogVerbose("%s: starting to parse doc file '%s'.",
1431 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1433 // the name of the class from the last "\membersection" command: we assume
1434 // that the following "\func" or "\constfunc" always documents a method of
1435 // this class (and it should always be like that in wxWidgets documentation)
1438 for ( const char *current
= buf
; current
- buf
< len
; current
++ ) {
1439 // FIXME parsing is awfully inefficient
1441 if ( *current
== '%' ) {
1442 // comment, skip until the end of line
1444 SkipUntil(¤t
, '\n');
1449 // all the command we're interested in start with '\\'
1450 while ( *current
!= '\\' && *current
!= '\0' ) {
1451 if ( *current
++ == '\n' )
1455 if ( *current
== '\0' ) {
1456 // no more TeX commands left
1460 current
++; // skip '\\'
1468 } foundCommand
= Nothing
;
1470 size_t lenMatch
= TryMatch(current
, "func");
1472 foundCommand
= Func
;
1475 lenMatch
= TryMatch(current
, "constfunc");
1477 foundCommand
= ConstFunc
;
1479 lenMatch
= TryMatch(current
, "membersection");
1482 foundCommand
= MemberSect
;
1486 if ( foundCommand
== Nothing
)
1489 current
+= lenMatch
;
1491 if ( !SkipSpaceUntil(¤t
, '{') ) {
1492 wxLogWarning("file %s(%d): '{' expected after \\func, "
1493 "\\constfunc or \\membersection.",
1494 m_filename
.c_str(), m_line
);
1501 if ( foundCommand
== MemberSect
) {
1502 // what follows has the form <classname>::<funcname>
1503 const char *startClass
= current
;
1504 if ( !SkipUntil(¤t
, ':') || *(current
+ 1) != ':' ) {
1505 wxLogWarning("file %s(%d): '::' expected after "
1506 "\\membersection.", m_filename
.c_str(), m_line
);
1509 classname
= wxString(startClass
, current
- startClass
);
1510 TeXUnfilter(&classname
);
1516 // extract the return type
1517 const char *startRetType
= current
;
1519 if ( !SkipUntil(¤t
, '}') ) {
1520 wxLogWarning("file %s(%d): '}' expected after return type",
1521 m_filename
.c_str(), m_line
);
1526 wxString returnType
= wxString(startRetType
, current
- startRetType
);
1527 TeXUnfilter(&returnType
);
1530 if ( !SkipSpaceUntil(¤t
, '{') ) {
1531 wxLogWarning("file %s(%d): '{' expected after return type",
1532 m_filename
.c_str(), m_line
);
1538 const char *funcEnd
= current
;
1539 if ( !SkipUntil(&funcEnd
, '}') ) {
1540 wxLogWarning("file %s(%d): '}' expected after function name",
1541 m_filename
.c_str(), m_line
);
1546 wxString funcName
= wxString(current
, funcEnd
- current
);
1547 current
= funcEnd
+ 1;
1549 // trim spaces from both sides
1550 funcName
.Trim(false);
1551 funcName
.Trim(true);
1553 // special cases: '$...$' may be used for LaTeX inline math, remove the
1555 if ( funcName
.Find('$') != wxNOT_FOUND
) {
1557 for ( const char *p
= funcName
.c_str(); *p
!= '\0'; p
++ ) {
1558 if ( *p
!= '$' && !isspace(*p
) )
1565 // \destruct{foo} is really ~foo
1566 if ( funcName
[0u] == '\\' ) {
1567 size_t len
= strlen("\\destruct{");
1568 if ( funcName(0, len
) != "\\destruct{" ) {
1569 wxLogWarning("file %s(%d): \\destruct expected",
1570 m_filename
.c_str(), m_line
);
1575 funcName
.erase(0, len
);
1576 funcName
.Prepend('~');
1578 if ( !SkipSpaceUntil(¤t
, '}') ) {
1579 wxLogWarning("file %s(%d): '}' expected after destructor",
1580 m_filename
.c_str(), m_line
);
1585 funcEnd
++; // there is an extra '}' to count
1588 TeXUnfilter(&funcName
);
1591 current
= funcEnd
+ 1; // skip '}'
1592 if ( !SkipSpaceUntil(¤t
, '{') ||
1593 (current
++, !SkipSpaceUntil(¤t
, '\\')) ) {
1594 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1595 m_filename
.c_str(), m_line
);
1600 wxArrayString paramNames
, paramTypes
, paramValues
;
1602 bool isVararg
= false;
1604 current
++; // skip '\\'
1605 lenMatch
= TryMatch(current
, "void");
1607 lenMatch
= TryMatch(current
, "param");
1608 while ( lenMatch
&& (current
- buf
< len
) ) {
1609 current
+= lenMatch
;
1611 // now come {paramtype}{paramname}
1612 wxString paramType
= ExtractStringBetweenBraces(¤t
);
1613 if ( !!paramType
) {
1614 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1615 if ( !!paramText
) {
1616 // the param declaration may contain default value
1617 wxString paramName
= paramText
.BeforeFirst('='),
1618 paramValue
= paramText
.AfterFirst('=');
1620 // sanitize all strings
1621 TeXUnfilter(¶mValue
);
1622 TeXUnfilter(¶mName
);
1623 TeXUnfilter(¶mType
);
1625 paramValues
.Add(paramValue
);
1626 paramNames
.Add(paramName
);
1627 paramTypes
.Add(paramType
);
1632 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1633 if ( paramText
== "..." ) {
1637 wxLogWarning("Parameters of '%s::%s' are in "
1639 classname
.c_str(), funcName
.c_str());
1644 current
= SkipSpaces(current
);
1645 if ( *current
== ',' || *current
== '}' ) {
1646 current
= SkipSpaces(++current
);
1648 lenMatch
= TryMatch(current
, "\\param");
1651 wxLogWarning("file %s(%d): ',' or '}' expected after "
1652 "'\\param'", m_filename
.c_str(), m_line
);
1658 // if we got here there was no '\\void', so must have some params
1659 if ( paramNames
.IsEmpty() ) {
1660 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1661 m_filename
.c_str(), m_line
);
1667 // verbose diagnostic output
1669 size_t param
, paramCount
= paramNames
.GetCount();
1670 for ( param
= 0; param
< paramCount
; param
++ ) {
1675 paramsAll
<< paramTypes
[param
] << ' ' << paramNames
[param
];
1678 wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
1679 m_filename
.c_str(), m_line
,
1684 foundCommand
== ConstFunc
? " const" : "");
1686 // store the info about the just found function
1687 ArrayMethodInfo
*methods
;
1688 int index
= m_classes
.Index(classname
);
1689 if ( index
== wxNOT_FOUND
) {
1690 m_classes
.Add(classname
);
1692 methods
= new ArrayMethodInfo
;
1693 m_methods
.Add(methods
);
1696 methods
= m_methods
[(size_t)index
];
1699 ArrayParamInfo params
;
1700 for ( param
= 0; param
< paramCount
; param
++ ) {
1701 params
.Add(new ParamInfo(paramTypes
[param
],
1703 paramValues
[param
]));
1706 MethodInfo
*method
= new MethodInfo(returnType
, funcName
, params
);
1707 if ( foundCommand
== ConstFunc
)
1708 method
->SetFlag(MethodInfo::Const
);
1710 method
->SetFlag(MethodInfo::Vararg
);
1712 methods
->Add(method
);
1717 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1718 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1723 bool DocManager::DumpDifferences(spContext
*ctxTop
) const
1725 typedef MMemberListT::const_iterator MemberIndex
;
1727 bool foundDiff
= false;
1729 // flag telling us whether the given class was found at all in the header
1730 size_t nClass
, countClassesInDocs
= m_classes
.GetCount();
1731 bool *classExists
= new bool[countClassesInDocs
];
1732 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1733 classExists
[nClass
] = false;
1736 // ctxTop is normally an spFile
1737 wxASSERT( ctxTop
->GetContextType() == SP_CTX_FILE
);
1739 const MMemberListT
& classes
= ctxTop
->GetMembers();
1740 for ( MemberIndex i
= classes
.begin(); i
!= classes
.end(); i
++ ) {
1741 spContext
*ctx
= *i
;
1742 if ( ctx
->GetContextType() != SP_CTX_CLASS
) {
1743 // TODO process also global functions, macros, ...
1747 spClass
*ctxClass
= (spClass
*)ctx
;
1748 const wxString
& nameClass
= ctxClass
->mName
;
1749 int index
= m_classes
.Index(nameClass
);
1750 if ( index
== wxNOT_FOUND
) {
1751 if ( !m_ignoreNames
.IgnoreClass(nameClass
) ) {
1754 wxLogError("Class '%s' is not documented at all.",
1758 // it makes no sense to check for its functions
1762 classExists
[index
] = true;
1765 // array of method descriptions for this class
1766 const ArrayMethodInfo
& methods
= *(m_methods
[index
]);
1767 size_t nMethod
, countMethods
= methods
.GetCount();
1769 // flags telling if we already processed given function
1770 bool *methodExists
= new bool[countMethods
];
1771 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1772 methodExists
[nMethod
] = false;
1775 wxArrayString aOverloadedMethods
;
1777 const MMemberListT
& functions
= ctxClass
->GetMembers();
1778 for ( MemberIndex j
= functions
.begin(); j
!= functions
.end(); j
++ ) {
1780 if ( ctx
->GetContextType() != SP_CTX_OPERATION
)
1783 spOperation
*ctxMethod
= (spOperation
*)ctx
;
1784 const wxString
& nameMethod
= ctxMethod
->mName
;
1786 // find all functions with the same name
1787 wxArrayInt aMethodsWithSameName
;
1788 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1789 if ( methods
[nMethod
]->GetName() == nameMethod
)
1790 aMethodsWithSameName
.Add(nMethod
);
1793 if ( aMethodsWithSameName
.IsEmpty() && ctxMethod
->IsPublic() ) {
1794 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1797 wxLogError("'%s::%s' is not documented.",
1799 nameMethod
.c_str());
1802 // don't check params
1805 else if ( aMethodsWithSameName
.GetCount() == 1 ) {
1806 index
= (size_t)aMethodsWithSameName
[0u];
1807 methodExists
[index
] = true;
1809 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1812 if ( !ctxMethod
->IsPublic() ) {
1813 wxLogWarning("'%s::%s' is documented but not public.",
1815 nameMethod
.c_str());
1818 // check that the flags match
1819 const MethodInfo
& method
= *(methods
[index
]);
1821 bool isVirtual
= ctxMethod
->mIsVirtual
;
1822 if ( isVirtual
!= method
.HasFlag(MethodInfo::Virtual
) ) {
1823 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1827 isVirtual
? "not " : "");
1830 bool isConst
= ctxMethod
->mIsConstant
;
1831 if ( isConst
!= method
.HasFlag(MethodInfo::Const
) ) {
1832 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1836 isConst
? "not " : "");
1839 // check that the params match
1840 const MMemberListT
& params
= ctxMethod
->GetMembers();
1842 if ( params
.size() != method
.GetParamCount() ) {
1843 wxLogError("Incorrect number of parameters for '%s::%s' "
1844 "in the docs: should be %d instead of %d.",
1847 params
.size(), method
.GetParamCount());
1851 for ( MemberIndex k
= params
.begin();
1856 // what else can a function have?
1857 wxASSERT( ctx
->GetContextType() == SP_CTX_PARAMETER
);
1859 spParameter
*ctxParam
= (spParameter
*)ctx
;
1860 const ParamInfo
& param
= method
.GetParam(nParam
);
1861 if ( m_checkParamNames
&&
1862 (param
.GetName() != ctxParam
->mName
) ) {
1865 wxLogError("Parameter #%d of '%s::%s' should be "
1866 "'%s' and not '%s'.",
1870 ctxParam
->mName
.c_str(),
1871 param
.GetName().c_str());
1876 if ( param
.GetType() != ctxParam
->mType
) {
1879 wxLogError("Type of parameter '%s' of '%s::%s' "
1880 "should be '%s' and not '%s'.",
1881 ctxParam
->mName
.c_str(),
1884 ctxParam
->mType
.c_str(),
1885 param
.GetType().GetName().c_str());
1890 if ( param
.GetDefValue() != ctxParam
->mInitVal
) {
1891 wxLogWarning("Default value of parameter '%s' of "
1892 "'%s::%s' should be '%s' and not "
1894 ctxParam
->mName
.c_str(),
1897 ctxParam
->mInitVal
.c_str(),
1898 param
.GetDefValue().c_str());
1904 // TODO OVER add real support for overloaded methods
1906 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1909 if ( aOverloadedMethods
.Index(nameMethod
) == wxNOT_FOUND
) {
1910 // mark all methods with this name as existing
1911 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1912 if ( methods
[nMethod
]->GetName() == nameMethod
)
1913 methodExists
[nMethod
] = true;
1916 aOverloadedMethods
.Add(nameMethod
);
1918 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1919 "stupid to find the right match - skipping "
1920 "the param and flags checks.",
1922 nameMethod
.c_str());
1924 //else: warning already given
1928 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1929 if ( !methodExists
[nMethod
] ) {
1930 const wxString
& nameMethod
= methods
[nMethod
]->GetName();
1931 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1934 wxLogError("'%s::%s' is documented but doesn't exist.",
1936 nameMethod
.c_str());
1941 delete [] methodExists
;
1944 // check that all classes we found in the docs really exist
1945 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1946 if ( !classExists
[nClass
] ) {
1949 wxLogError("Class '%s' is documented but doesn't exist.",
1950 m_classes
[nClass
].c_str());
1954 delete [] classExists
;
1959 DocManager::~DocManager()
1961 WX_CLEAR_ARRAY(m_methods
);
1964 // ---------------------------------------------------------------------------
1965 // IgnoreNamesHandler implementation
1966 // ---------------------------------------------------------------------------
1968 int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry
*first
,
1969 IgnoreListEntry
*second
)
1971 // first compare the classes
1972 int rc
= first
->m_classname
.Cmp(second
->m_classname
);
1974 rc
= first
->m_funcname
.Cmp(second
->m_funcname
);
1979 bool IgnoreNamesHandler::AddNamesFromFile(const wxString
& filename
)
1981 wxFile
file(filename
, wxFile::read
);
1982 if ( !file
.IsOpened() )
1985 off_t len
= file
.Length();
1986 if ( len
== wxInvalidOffset
)
1989 char *buf
= new char[len
+ 1];
1992 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1999 for ( const char *current
= buf
; ; current
++ ) {
2001 // skip DOS line separator
2002 if ( *current
== '\r' )
2006 if ( *current
== '\n' || *current
== '\0' ) {
2007 if ( line
[0u] != '#' ) {
2008 if ( line
.Find(':') != wxNOT_FOUND
) {
2009 wxString classname
= line
.BeforeFirst(':'),
2010 funcname
= line
.AfterLast(':');
2011 m_ignore
.Add(new IgnoreListEntry(classname
, funcname
));
2015 m_ignore
.Add(new IgnoreListEntry(line
, ""));
2020 if ( *current
== '\0' )
2035 // -----------------------------------------------------------------------------
2036 // global function implementation
2037 // -----------------------------------------------------------------------------
2039 static wxString
MakeLabel(const char *classname
, const char *funcname
)
2041 wxString
label(classname
);
2042 if ( funcname
&& funcname
[0] == '\\' ) {
2043 // we may have some special TeX macro - so far only \destruct exists,
2044 // but may be later others will be added
2045 static const char *macros
[] = { "destruct" };
2046 static const char *replacement
[] = { "dtor" };
2049 for ( n
= 0; n
< WXSIZEOF(macros
); n
++ ) {
2050 if ( strncmp(funcname
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) {
2056 if ( n
== WXSIZEOF(macros
) ) {
2057 wxLogWarning("unknown function name '%s' - leaving as is.",
2061 funcname
= replacement
[n
];
2066 // special treatment for operatorXXX() stuff because the C operators
2067 // are not valid in LaTeX labels
2069 if ( wxString(funcname
).StartsWith("operator", &oper
) ) {
2070 label
<< "operator";
2083 for ( n
= 0; n
< WXSIZEOF(operatorNames
); n
++ ) {
2084 if ( oper
== operatorNames
[n
].oper
) {
2085 label
<< operatorNames
[n
].name
;
2091 if ( n
== WXSIZEOF(operatorNames
) ) {
2092 wxLogWarning("unknown operator '%s' - making dummy label.",
2098 else // simply use the func name
2109 static wxString
MakeHelpref(const char *argument
)
2112 helpref
<< "\\helpref{" << argument
<< "}{" << MakeLabel(argument
) << '}';
2117 static void TeXFilter(wxString
* str
)
2119 // TeX special which can be quoted (don't include backslash nor braces as
2121 static wxRegEx
reNonSpecialSpecials("[#$%&_]"),
2125 reNonSpecialSpecials
.ReplaceAll(str
, "\\\\\\0");
2127 // can't quote these ones as they produce accents when preceded by
2128 // backslash, so put them inside verb
2129 reAccents
.ReplaceAll(str
, "\\\\verb|\\0|");
2132 static void TeXUnfilter(wxString
* str
)
2134 // FIXME may be done much more quickly
2139 static wxRegEx
reNonSpecialSpecials("\\\\([#$%&_{}])"),
2140 reAccents("\\\\verb\\|([~^])\\|");
2142 reNonSpecialSpecials
.ReplaceAll(str
, "\\1");
2143 reAccents
.ReplaceAll(str
, "\\1");
2146 static wxString
GetAllComments(const spContext
& ctx
)
2149 const MCommentListT
& commentsList
= ctx
.GetCommentList();
2150 for ( MCommentListT::const_iterator i
= commentsList
.begin();
2151 i
!= commentsList
.end();
2153 wxString comment
= (*i
)->GetText();
2155 // don't take comments like "// ----------" &c
2156 comment
.Trim(false);
2158 comment
== wxString(comment
[0u], comment
.length() - 1) + '\n' )
2161 comments
<< comment
;
2167 static const char *GetCurrentTime(const char *timeFormat
)
2169 static char s_timeBuffer
[128];
2174 ptmNow
= localtime(&timeNow
);
2176 strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
);
2178 return s_timeBuffer
;
2181 static const wxString
GetVersionString()
2183 wxString version
= "$Revision$";
2184 wxRegEx("^\\$Revision$$").ReplaceFirst(&version
, "\\1");
2190 Revision 1.29 2004/06/17 19:00:22 ABX
2191 Warning fixes. Code cleanup. Whitespaces and tabs removed.
2193 Revision 1.28 2004/05/25 11:19:57 JS
2196 Revision 1.27 2003/10/13 17:21:30 MBN
2199 Revision 1.26 2003/09/29 15:18:35 MBN
2200 (Blind) compilation fix for Sun compiler.
2202 Revision 1.25 2003/09/03 17:39:27 MBN
2205 Revision 1.24 2003/08/13 22:59:37 VZ
2208 Revision 1.23 2003/06/13 17:05:43 VZ
2209 quote '|' inside regexes (fixes dump mode); fixed crash due to strange HelpGenApp code
2211 Revision 1.22 2002/01/21 21:18:50 JS
2212 Now adds 'include file' heading
2214 Revision 1.21 2002/01/04 11:06:09 JS
2215 Fixed missing membersections bug and also bug with functions not being written
2218 Revision 1.20 2002/01/03 14:23:33 JS
2219 Added code to make it not duplicate membersections for overloaded functions
2221 Revision 1.19 2002/01/03 13:34:12 JS
2222 Added FlushAll to CloseClass, otherwise text was only flushed right at the end,
2223 and appeared in one file.
2225 Revision 1.18 2002/01/03 12:02:47 JS
2226 Added main() and corrected VC++ project settings
2228 Revision 1.17 2001/11/30 21:43:35 VZ
2229 now the methods are sorted in the correct order in the generated docs
2231 Revision 1.16 2001/11/28 19:27:33 VZ
2232 HelpGen doesn't work in GUI mode
2234 Revision 1.15 2001/11/22 21:59:58 GD
2235 use "..." instead of <...> for wx headers
2237 Revision 1.14 2001/07/19 13:51:29 VZ
2238 fixes to version string
2240 Revision 1.13 2001/07/19 13:44:57 VZ
2241 1. compilation fixes
2242 2. don't quote special characters inside verbatim environment
2244 Revision 1.12 2000/10/09 13:53:33 juliansmart
2246 Doc corrections; added HelpGen project files
2248 Revision 1.11 2000/07/15 19:50:42 cvsuser
2251 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
2252 don't trasnform output dir name to lower case
2254 Revision 1.10 2000/03/11 10:05:23 VS
2255 now compiles with wxBase
2257 Revision 1.9 2000/01/16 13:25:21 VS
2258 compilation fixes (gcc)
2260 Revision 1.8 1999/09/13 14:29:39 JS
2262 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2263 into src for simplicity; added VC++ 5 project file
2265 Revision 1.7 1999/02/21 22:32:32 VZ
2266 1. more C++ parser fixes - now it almost parses wx/string.h
2267 a) #if/#ifdef/#else (very) limited support
2268 b) param type fix - now indirection chars are correctly handled
2269 c) class/struct/union distinction
2270 d) public/private fixes
2271 e) Dump() function added - very useful for debugging
2273 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2274 by default, and this option switches it on)
2276 Revision 1.6 1999/02/20 23:00:26 VZ
2277 1. new 'diff' mode which seems to work
2278 2. output files are not overwritten in 'dmup' mode
2279 3. fixes for better handling of const functions and operators
2280 ----------------------------
2282 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2283 1. Parser improvements
2284 a) const and virtual methods are parsed correctly (not static yet)
2285 b) "const" which is part of the return type is not swallowed
2287 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2288 "//---------" kind comments discarded now.
2289 ----------------------------
2291 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2293 some tweaks to HelpGen
2294 ----------------------------
2296 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2298 HelpGen starting to compile with VC++
2299 ----------------------------
2301 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2303 supports typedefs, generates "See also:" and adds "virtual " for virtual
2305 ----------------------------
2307 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2309 HelpGen is a prototype of the tool for automatic generation of the .tex files
2310 for wxWidgets documentation from C++ headers
2313 /* vi: set tw=80 et ts=4 sw=4: */