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(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(MethodInfo
*, ArrayMethodInfo
);
509 WX_DEFINE_ARRAY(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 wxWindows 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()
882 size_t count
= m_arrayFuncDocs
.GetCount();
885 FunctionDocEntry::classname
= m_classname
;
887 m_arrayFuncDocs
.Sort(FunctionDocEntry::Compare
);
889 // Now examine each first line and if it's been seen, cut it
890 // off (it's a duplicate \membersection)
891 wxHashTable
membersections(wxKEY_STRING
);
893 for ( n
= 0; n
< count
; n
++ )
895 wxString
section(m_arrayFuncDocs
[n
].text
);
897 // Strip leading whitespace
898 int pos
= section
.Find("\\membersection");
901 section
= section
.Mid(pos
);
904 wxString
ms(section
.BeforeFirst(wxT('\n')));
905 if (membersections
.Get(ms
))
907 m_arrayFuncDocs
[n
].text
= section
.AfterFirst(wxT('\n'));
911 membersections
.Put(ms
, & membersections
);
915 for ( n
= 0; n
< count
; n
++ ) {
916 m_file
.WriteTeX(m_arrayFuncDocs
[n
].text
);
919 m_arrayFuncDocs
.Empty();
928 void HelpGenVisitor::EndVisit()
934 m_fileHeader
.Empty();
937 if (m_file
.IsOpened())
943 wxLogVerbose("%s: finished generating for the current file.",
944 GetCurrentTime("%H:%M:%S"));
947 void HelpGenVisitor::VisitFile( spFile
& file
)
949 m_fileHeader
= file
.mFileName
;
950 wxLogVerbose("%s: started generating docs for classes from file '%s'...",
951 GetCurrentTime("%H:%M:%S"), m_fileHeader
.c_str());
954 void HelpGenVisitor::VisitClass( spClass
& cl
)
958 if (m_file
.IsOpened())
964 wxString name
= cl
.GetName();
966 if ( m_ignoreNames
.IgnoreClass(name
) ) {
967 wxLogVerbose("Skipping ignored class '%s'.", name
.c_str());
972 // the file name is built from the class name by removing the leading "wx"
973 // if any and converting it to the lower case
975 if ( name(0, 2) == "wx" ) {
976 filename
<< name
.c_str() + 2;
982 filename
.MakeLower();
984 filename
.Prepend(m_directoryOut
);
986 if ( !m_overwrite
&& wxFile::Exists(filename
) ) {
987 wxLogError("Won't overwrite existing file '%s' - please use '-f'.",
993 m_inClass
= m_file
.Open(filename
, wxFile::write
);
995 wxLogError("Can't generate documentation for the class '%s'.",
1002 m_inTypesSection
= FALSE
;
1004 wxLogInfo("Created new file '%s' for class '%s'.",
1005 filename
.c_str(), name
.c_str());
1007 // write out the header
1009 header
.Printf("%%\n"
1010 "%% automatically generated by HelpGen %s from\n"
1015 "\\section{\\class{%s}}\\label{%s}\n\n",
1016 GetVersionString().c_str(),
1017 m_fileHeader
.c_str(),
1018 GetCurrentTime("%d/%b/%y %H:%M:%S"),
1020 wxString(name
).MakeLower().c_str());
1022 m_file
.WriteVerbatim(header
);
1024 // the entire text we're writing to file
1027 // if the header includes other headers they must be related to it... try to
1028 // automatically generate the "See also" clause
1029 if ( !m_headers
.IsEmpty() ) {
1030 // correspondence between wxWindows headers and class names
1031 static const char *headers
[] = {
1040 // NULL here means not to insert anything in "See also" for the
1041 // corresponding header
1042 static const char *classes
[] = {
1051 wxASSERT_MSG( WXSIZEOF(headers
) == WXSIZEOF(classes
),
1052 "arrays must be in sync!" );
1054 wxArrayInt interestingClasses
;
1056 size_t count
= m_headers
.Count(), index
;
1057 for ( size_t n
= 0; n
< count
; n
++ ) {
1058 wxString baseHeaderName
= m_headers
[n
].Before('.');
1059 if ( baseHeaderName(0, 3) != "wx/" )
1062 baseHeaderName
.erase(0, 3);
1063 for ( index
= 0; index
< WXSIZEOF(headers
); index
++ ) {
1064 if ( Stricmp(baseHeaderName
, headers
[index
]) == 0 )
1068 if ( (index
< WXSIZEOF(headers
)) && classes
[index
] ) {
1069 // interesting header
1070 interestingClasses
.Add(index
);
1074 if ( !interestingClasses
.IsEmpty() ) {
1075 // do generate "See also" clause
1076 totalText
<< "\\wxheading{See also:}\n\n";
1078 count
= interestingClasses
.Count();
1079 for ( index
= 0; index
< count
; index
++ ) {
1083 totalText
<< MakeHelpref(classes
[interestingClasses
[index
]]);
1086 totalText
<< "\n\n";
1090 // the comment before the class generally explains what is it for so put it
1091 // in place of the class description
1092 if ( cl
.HasComments() ) {
1093 wxString comment
= GetAllComments(cl
);
1095 totalText
<< '\n' << comment
<< '\n';
1098 // derived from section
1099 wxString derived
= "\\wxheading{Derived from}\n\n";
1101 const StrListT
& baseClasses
= cl
.mSuperClassNames
;
1102 if ( baseClasses
.size() == 0 ) {
1103 derived
<< "No base class";
1107 for ( StrListT::const_iterator i
= baseClasses
.begin();
1108 i
!= baseClasses
.end();
1111 // separate from the previous one
1112 derived
<< "\\\\\n";
1118 wxString baseclass
= *i
;
1119 derived
<< "\\helpref{" << baseclass
<< "}";
1120 derived
<< "{" << baseclass
.MakeLower() << "}";
1123 totalText
<< derived
<< "\n\n";
1125 // include file section
1126 wxString includeFile
= "\\wxheading{Include files}\n\n";
1127 includeFile
<< "<" << m_fileHeader
<< ">";
1129 totalText
<< includeFile
<< "\n\n";
1131 // write all this to file
1132 m_file
.WriteTeX(totalText
);
1134 // if there were any enums/typedefs before, insert their documentation now
1135 InsertDataStructuresHeader();
1136 InsertTypedefDocs();
1142 void HelpGenVisitor::VisitEnumeration( spEnumeration
& en
)
1146 if ( m_inMethodSection
) {
1147 // FIXME that's a bug, but tell the user aboit it nevertheless... we
1148 // should be smart enough to process even the enums which come after the
1150 wxLogWarning("enum '%s' ignored, please put it before the class "
1151 "methods.", en
.GetName().c_str());
1155 // simply copy the enum text in the docs
1156 wxString enumeration
= GetAllComments(en
),
1159 enumerationVerb
<< "\\begin{verbatim}\n"
1161 << "\n\\end{verbatim}\n";
1163 // remember for later use if we're not inside a class yet
1165 m_storedEnums
.Add(enumeration
);
1166 m_storedEnumsVerb
.Add(enumerationVerb
);
1169 // write the header for this section if not done yet
1170 InsertDataStructuresHeader();
1172 m_file
.WriteTeX(enumeration
);
1173 m_file
.WriteVerbatim(enumerationVerb
);
1174 m_file
.WriteVerbatim('\n');
1178 void HelpGenVisitor::VisitTypeDef( spTypeDef
& td
)
1182 if ( m_inMethodSection
) {
1183 // FIXME that's a bug, but tell the user aboit it nevertheless...
1184 wxLogWarning("typedef '%s' ignored, please put it before the class "
1185 "methods.", td
.GetName().c_str());
1189 wxString typedefdoc
;
1190 typedefdoc
<< "{\\small \\begin{verbatim}\n"
1191 << "typedef " << td
.mOriginalType
<< ' ' << td
.GetName()
1192 << "\n\\end{verbatim}}\n"
1193 << GetAllComments(td
);
1195 // remember for later use if we're not inside a class yet
1197 if ( !m_textStoredTypedefs
.IsEmpty() ) {
1198 m_textStoredTypedefs
<< '\n';
1201 m_textStoredTypedefs
<< typedefdoc
;
1204 // write the header for this section if not done yet
1205 InsertDataStructuresHeader();
1208 m_file
.WriteTeX(typedefdoc
);
1212 void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine
& pd
)
1214 switch ( pd
.GetStatementType() ) {
1215 case SP_PREP_DEF_INCLUDE_FILE
:
1216 m_headers
.Add(pd
.CPP_GetIncludedFileNeme());
1219 case SP_PREP_DEF_DEFINE_SYMBOL
:
1220 // TODO decide if it's a constant and document it if it is
1225 void HelpGenVisitor::VisitAttribute( spAttribute
& attr
)
1229 // only document the public member variables
1230 if ( !m_inClass
|| !attr
.IsPublic() )
1233 wxLogWarning("Ignoring member variable '%s'.", attr
.GetName().c_str());
1236 void HelpGenVisitor::VisitOperation( spOperation
& op
)
1241 // we don't generate docs right now - either we ignore this class
1242 // entirely or we couldn't open the file
1246 if ( !op
.IsInClass() ) {
1247 // TODO document global functions
1248 wxLogWarning("skipped global function '%s'.", op
.GetName().c_str());
1253 if ( op
.mVisibility
== SP_VIS_PRIVATE
) {
1254 // FIXME should we document protected functions?
1258 m_classname
= op
.GetClass().GetName();
1259 wxString funcname
= op
.GetName();
1261 if ( m_ignoreNames
.IgnoreMethod(m_classname
, funcname
) ) {
1262 wxLogVerbose("Skipping ignored '%s::%s'.",
1263 m_classname
.c_str(), funcname
.c_str());
1268 InsertMethodsHeader();
1271 m_funcName
= funcname
;
1272 m_isFirstParam
= TRUE
;
1274 m_textStoredFunctionComment
= GetAllComments(op
);
1276 // start function documentation
1279 // check for the special case of dtor
1281 if ( (funcname
[0u] == '~') && (m_classname
== funcname
.c_str() + 1) ) {
1282 dtor
.Printf("\\destruct{%s}", m_classname
.c_str());
1286 m_textFunc
.Printf("\n"
1287 "\\membersection{%s::%s}\\label{%s}\n",
1288 m_classname
.c_str(), funcname
.c_str(),
1289 MakeLabel(m_classname
, funcname
).c_str());
1293 "\\%sfunc{%s%s}{%s}{",
1294 op
.mIsConstant
? "const" : "",
1295 op
.mIsVirtual
? "virtual " : "",
1296 op
.mRetType
.c_str(),
1301 void HelpGenVisitor::VisitParameter( spParameter
& param
)
1303 if ( m_funcName
.empty() )
1306 if ( m_isFirstParam
) {
1307 m_isFirstParam
= FALSE
;
1313 m_textFunc
<< "\\param{" << param
.mType
<< " }{" << param
.GetName();
1314 wxString defvalue
= param
.mInitVal
;
1315 if ( !defvalue
.IsEmpty() ) {
1316 m_textFunc
<< " = " << defvalue
;
1322 // ---------------------------------------------------------------------------
1324 // ---------------------------------------------------------------------------
1326 DocManager::DocManager(bool checkParamNames
)
1328 m_checkParamNames
= checkParamNames
;
1331 size_t DocManager::TryMatch(const char *str
, const char *match
)
1333 size_t lenMatch
= 0;
1334 while ( str
[lenMatch
] == match
[lenMatch
] ) {
1337 if ( match
[lenMatch
] == '\0' )
1344 bool DocManager::SkipUntil(const char **pp
, char c
)
1346 const char *p
= *pp
;
1362 bool DocManager::SkipSpaceUntil(const char **pp
, char c
)
1364 const char *p
= *pp
;
1366 if ( !isspace(*p
) || *p
== '\0' )
1380 wxString
DocManager::ExtractStringBetweenBraces(const char **pp
)
1384 if ( !SkipSpaceUntil(pp
, '{') ) {
1385 wxLogWarning("file %s(%d): '{' expected after '\\param'",
1386 m_filename
.c_str(), m_line
);
1390 const char *startParam
= ++*pp
; // skip '{'
1392 if ( !SkipUntil(pp
, '}') ) {
1393 wxLogWarning("file %s(%d): '}' expected after '\\param'",
1394 m_filename
.c_str(), m_line
);
1397 result
= wxString(startParam
, (*pp
)++ - startParam
);
1404 bool DocManager::ParseTeXFile(const wxString
& filename
)
1406 m_filename
= filename
;
1408 wxFile
file(m_filename
, wxFile::read
);
1409 if ( !file
.IsOpened() )
1412 off_t len
= file
.Length();
1413 if ( len
== wxInvalidOffset
)
1416 char *buf
= new char[len
+ 1];
1419 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1425 // reinit everything
1428 wxLogVerbose("%s: starting to parse doc file '%s'.",
1429 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1431 // the name of the class from the last "\membersection" command: we assume
1432 // that the following "\func" or "\constfunc" always documents a method of
1433 // this class (and it should always be like that in wxWindows documentation)
1436 for ( const char *current
= buf
; current
- buf
< len
; current
++ ) {
1437 // FIXME parsing is awfully inefficient
1439 if ( *current
== '%' ) {
1440 // comment, skip until the end of line
1442 SkipUntil(¤t
, '\n');
1447 // all the command we're interested in start with '\\'
1448 while ( *current
!= '\\' && *current
!= '\0' ) {
1449 if ( *current
++ == '\n' )
1453 if ( *current
== '\0' ) {
1454 // no more TeX commands left
1458 current
++; // skip '\\'
1466 } foundCommand
= Nothing
;
1468 size_t lenMatch
= TryMatch(current
, "func");
1470 foundCommand
= Func
;
1473 lenMatch
= TryMatch(current
, "constfunc");
1475 foundCommand
= ConstFunc
;
1477 lenMatch
= TryMatch(current
, "membersection");
1480 foundCommand
= MemberSect
;
1484 if ( foundCommand
== Nothing
)
1487 current
+= lenMatch
;
1489 if ( !SkipSpaceUntil(¤t
, '{') ) {
1490 wxLogWarning("file %s(%d): '{' expected after \\func, "
1491 "\\constfunc or \\membersection.",
1492 m_filename
.c_str(), m_line
);
1499 if ( foundCommand
== MemberSect
) {
1500 // what follows has the form <classname>::<funcname>
1501 const char *startClass
= current
;
1502 if ( !SkipUntil(¤t
, ':') || *(current
+ 1) != ':' ) {
1503 wxLogWarning("file %s(%d): '::' expected after "
1504 "\\membersection.", m_filename
.c_str(), m_line
);
1507 classname
= wxString(startClass
, current
- startClass
);
1508 TeXUnfilter(&classname
);
1514 // extract the return type
1515 const char *startRetType
= current
;
1517 if ( !SkipUntil(¤t
, '}') ) {
1518 wxLogWarning("file %s(%d): '}' expected after return type",
1519 m_filename
.c_str(), m_line
);
1524 wxString returnType
= wxString(startRetType
, current
- startRetType
);
1525 TeXUnfilter(&returnType
);
1528 if ( !SkipSpaceUntil(¤t
, '{') ) {
1529 wxLogWarning("file %s(%d): '{' expected after return type",
1530 m_filename
.c_str(), m_line
);
1536 const char *funcEnd
= current
;
1537 if ( !SkipUntil(&funcEnd
, '}') ) {
1538 wxLogWarning("file %s(%d): '}' expected after function name",
1539 m_filename
.c_str(), m_line
);
1544 wxString funcName
= wxString(current
, funcEnd
- current
);
1545 current
= funcEnd
+ 1;
1547 // trim spaces from both sides
1548 funcName
.Trim(FALSE
);
1549 funcName
.Trim(TRUE
);
1551 // special cases: '$...$' may be used for LaTeX inline math, remove the
1553 if ( funcName
.Find('$') != wxNOT_FOUND
) {
1555 for ( const char *p
= funcName
.c_str(); *p
!= '\0'; p
++ ) {
1556 if ( *p
!= '$' && !isspace(*p
) )
1563 // \destruct{foo} is really ~foo
1564 if ( funcName
[0u] == '\\' ) {
1565 size_t len
= strlen("\\destruct{");
1566 if ( funcName(0, len
) != "\\destruct{" ) {
1567 wxLogWarning("file %s(%d): \\destruct expected",
1568 m_filename
.c_str(), m_line
);
1573 funcName
.erase(0, len
);
1574 funcName
.Prepend('~');
1576 if ( !SkipSpaceUntil(¤t
, '}') ) {
1577 wxLogWarning("file %s(%d): '}' expected after destructor",
1578 m_filename
.c_str(), m_line
);
1583 funcEnd
++; // there is an extra '}' to count
1586 TeXUnfilter(&funcName
);
1589 current
= funcEnd
+ 1; // skip '}'
1590 if ( !SkipSpaceUntil(¤t
, '{') ||
1591 (current
++, !SkipSpaceUntil(¤t
, '\\')) ) {
1592 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1593 m_filename
.c_str(), m_line
);
1598 wxArrayString paramNames
, paramTypes
, paramValues
;
1600 bool isVararg
= FALSE
;
1602 current
++; // skip '\\'
1603 lenMatch
= TryMatch(current
, "void");
1605 lenMatch
= TryMatch(current
, "param");
1606 while ( lenMatch
&& (current
- buf
< len
) ) {
1607 current
+= lenMatch
;
1609 // now come {paramtype}{paramname}
1610 wxString paramType
= ExtractStringBetweenBraces(¤t
);
1611 if ( !!paramType
) {
1612 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1613 if ( !!paramText
) {
1614 // the param declaration may contain default value
1615 wxString paramName
= paramText
.BeforeFirst('='),
1616 paramValue
= paramText
.AfterFirst('=');
1618 // sanitize all strings
1619 TeXUnfilter(¶mValue
);
1620 TeXUnfilter(¶mName
);
1621 TeXUnfilter(¶mType
);
1623 paramValues
.Add(paramValue
);
1624 paramNames
.Add(paramName
);
1625 paramTypes
.Add(paramType
);
1630 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1631 if ( paramText
== "..." ) {
1635 wxLogWarning("Parameters of '%s::%s' are in "
1637 classname
.c_str(), funcName
.c_str());
1642 current
= SkipSpaces(current
);
1643 if ( *current
== ',' || *current
== '}' ) {
1644 current
= SkipSpaces(++current
);
1646 lenMatch
= TryMatch(current
, "\\param");
1649 wxLogWarning("file %s(%d): ',' or '}' expected after "
1650 "'\\param'", m_filename
.c_str(), m_line
);
1656 // if we got here there was no '\\void', so must have some params
1657 if ( paramNames
.IsEmpty() ) {
1658 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1659 m_filename
.c_str(), m_line
);
1665 // verbose diagnostic output
1667 size_t param
, paramCount
= paramNames
.GetCount();
1668 for ( param
= 0; param
< paramCount
; param
++ ) {
1673 paramsAll
<< paramTypes
[param
] << ' ' << paramNames
[param
];
1676 wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
1677 m_filename
.c_str(), m_line
,
1682 foundCommand
== ConstFunc
? " const" : "");
1684 // store the info about the just found function
1685 ArrayMethodInfo
*methods
;
1686 int index
= m_classes
.Index(classname
);
1687 if ( index
== wxNOT_FOUND
) {
1688 m_classes
.Add(classname
);
1690 methods
= new ArrayMethodInfo
;
1691 m_methods
.Add(methods
);
1694 methods
= m_methods
[(size_t)index
];
1697 ArrayParamInfo params
;
1698 for ( param
= 0; param
< paramCount
; param
++ ) {
1699 params
.Add(new ParamInfo(paramTypes
[param
],
1701 paramValues
[param
]));
1704 MethodInfo
*method
= new MethodInfo(returnType
, funcName
, params
);
1705 if ( foundCommand
== ConstFunc
)
1706 method
->SetFlag(MethodInfo::Const
);
1708 method
->SetFlag(MethodInfo::Vararg
);
1710 methods
->Add(method
);
1715 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1716 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1721 bool DocManager::DumpDifferences(spContext
*ctxTop
) const
1723 typedef MMemberListT::const_iterator MemberIndex
;
1725 bool foundDiff
= FALSE
;
1727 // flag telling us whether the given class was found at all in the header
1728 size_t nClass
, countClassesInDocs
= m_classes
.GetCount();
1729 bool *classExists
= new bool[countClassesInDocs
];
1730 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1731 classExists
[nClass
] = FALSE
;
1734 // ctxTop is normally an spFile
1735 wxASSERT( ctxTop
->GetContextType() == SP_CTX_FILE
);
1737 const MMemberListT
& classes
= ctxTop
->GetMembers();
1738 for ( MemberIndex i
= classes
.begin(); i
!= classes
.end(); i
++ ) {
1739 spContext
*ctx
= *i
;
1740 if ( ctx
->GetContextType() != SP_CTX_CLASS
) {
1741 // TODO process also global functions, macros, ...
1745 spClass
*ctxClass
= (spClass
*)ctx
;
1746 const wxString
& nameClass
= ctxClass
->mName
;
1747 int index
= m_classes
.Index(nameClass
);
1748 if ( index
== wxNOT_FOUND
) {
1749 if ( !m_ignoreNames
.IgnoreClass(nameClass
) ) {
1752 wxLogError("Class '%s' is not documented at all.",
1756 // it makes no sense to check for its functions
1760 classExists
[index
] = TRUE
;
1763 // array of method descriptions for this class
1764 const ArrayMethodInfo
& methods
= *(m_methods
[index
]);
1765 size_t nMethod
, countMethods
= methods
.GetCount();
1767 // flags telling if we already processed given function
1768 bool *methodExists
= new bool[countMethods
];
1769 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1770 methodExists
[nMethod
] = FALSE
;
1773 wxArrayString aOverloadedMethods
;
1775 const MMemberListT
& functions
= ctxClass
->GetMembers();
1776 for ( MemberIndex j
= functions
.begin(); j
!= functions
.end(); j
++ ) {
1778 if ( ctx
->GetContextType() != SP_CTX_OPERATION
)
1781 spOperation
*ctxMethod
= (spOperation
*)ctx
;
1782 const wxString
& nameMethod
= ctxMethod
->mName
;
1784 // find all functions with the same name
1785 wxArrayInt aMethodsWithSameName
;
1786 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1787 if ( methods
[nMethod
]->GetName() == nameMethod
)
1788 aMethodsWithSameName
.Add(nMethod
);
1791 if ( aMethodsWithSameName
.IsEmpty() && ctxMethod
->IsPublic() ) {
1792 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1795 wxLogError("'%s::%s' is not documented.",
1797 nameMethod
.c_str());
1800 // don't check params
1803 else if ( aMethodsWithSameName
.GetCount() == 1 ) {
1804 index
= (size_t)aMethodsWithSameName
[0u];
1805 methodExists
[index
] = TRUE
;
1807 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1810 if ( !ctxMethod
->IsPublic() ) {
1811 wxLogWarning("'%s::%s' is documented but not public.",
1813 nameMethod
.c_str());
1816 // check that the flags match
1817 const MethodInfo
& method
= *(methods
[index
]);
1819 bool isVirtual
= ctxMethod
->mIsVirtual
;
1820 if ( isVirtual
!= method
.HasFlag(MethodInfo::Virtual
) ) {
1821 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1825 isVirtual
? "not " : "");
1828 bool isConst
= ctxMethod
->mIsConstant
;
1829 if ( isConst
!= method
.HasFlag(MethodInfo::Const
) ) {
1830 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1834 isConst
? "not " : "");
1837 // check that the params match
1838 const MMemberListT
& params
= ctxMethod
->GetMembers();
1840 if ( params
.size() != method
.GetParamCount() ) {
1841 wxLogError("Incorrect number of parameters for '%s::%s' "
1842 "in the docs: should be %d instead of %d.",
1845 params
.size(), method
.GetParamCount());
1849 for ( MemberIndex k
= params
.begin();
1854 // what else can a function have?
1855 wxASSERT( ctx
->GetContextType() == SP_CTX_PARAMETER
);
1857 spParameter
*ctxParam
= (spParameter
*)ctx
;
1858 const ParamInfo
& param
= method
.GetParam(nParam
);
1859 if ( m_checkParamNames
&&
1860 (param
.GetName() != ctxParam
->mName
) ) {
1863 wxLogError("Parameter #%d of '%s::%s' should be "
1864 "'%s' and not '%s'.",
1868 ctxParam
->mName
.c_str(),
1869 param
.GetName().c_str());
1874 if ( param
.GetType() != ctxParam
->mType
) {
1877 wxLogError("Type of parameter '%s' of '%s::%s' "
1878 "should be '%s' and not '%s'.",
1879 ctxParam
->mName
.c_str(),
1882 ctxParam
->mType
.c_str(),
1883 param
.GetType().GetName().c_str());
1888 if ( param
.GetDefValue() != ctxParam
->mInitVal
) {
1889 wxLogWarning("Default value of parameter '%s' of "
1890 "'%s::%s' should be '%s' and not "
1892 ctxParam
->mName
.c_str(),
1895 ctxParam
->mInitVal
.c_str(),
1896 param
.GetDefValue().c_str());
1902 // TODO OVER add real support for overloaded methods
1904 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1907 if ( aOverloadedMethods
.Index(nameMethod
) == wxNOT_FOUND
) {
1908 // mark all methods with this name as existing
1909 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1910 if ( methods
[nMethod
]->GetName() == nameMethod
)
1911 methodExists
[nMethod
] = TRUE
;
1914 aOverloadedMethods
.Add(nameMethod
);
1916 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1917 "stupid to find the right match - skipping "
1918 "the param and flags checks.",
1920 nameMethod
.c_str());
1922 //else: warning already given
1926 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1927 if ( !methodExists
[nMethod
] ) {
1928 const wxString
& nameMethod
= methods
[nMethod
]->GetName();
1929 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1932 wxLogError("'%s::%s' is documented but doesn't exist.",
1934 nameMethod
.c_str());
1939 delete [] methodExists
;
1942 // check that all classes we found in the docs really exist
1943 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1944 if ( !classExists
[nClass
] ) {
1947 wxLogError("Class '%s' is documented but doesn't exist.",
1948 m_classes
[nClass
].c_str());
1952 delete [] classExists
;
1957 DocManager::~DocManager()
1959 WX_CLEAR_ARRAY(m_methods
);
1962 // ---------------------------------------------------------------------------
1963 // IgnoreNamesHandler implementation
1964 // ---------------------------------------------------------------------------
1966 int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry
*first
,
1967 IgnoreListEntry
*second
)
1969 // first compare the classes
1970 int rc
= first
->m_classname
.Cmp(second
->m_classname
);
1972 rc
= first
->m_funcname
.Cmp(second
->m_funcname
);
1977 bool IgnoreNamesHandler::AddNamesFromFile(const wxString
& filename
)
1979 wxFile
file(filename
, wxFile::read
);
1980 if ( !file
.IsOpened() )
1983 off_t len
= file
.Length();
1984 if ( len
== wxInvalidOffset
)
1987 char *buf
= new char[len
+ 1];
1990 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1997 for ( const char *current
= buf
; ; current
++ ) {
1999 // skip DOS line separator
2000 if ( *current
== '\r' )
2004 if ( *current
== '\n' || *current
== '\0' ) {
2005 if ( line
[0u] != '#' ) {
2006 if ( line
.Find(':') != wxNOT_FOUND
) {
2007 wxString classname
= line
.BeforeFirst(':'),
2008 funcname
= line
.AfterLast(':');
2009 m_ignore
.Add(new IgnoreListEntry(classname
, funcname
));
2013 m_ignore
.Add(new IgnoreListEntry(line
, ""));
2018 if ( *current
== '\0' )
2033 // -----------------------------------------------------------------------------
2034 // global function implementation
2035 // -----------------------------------------------------------------------------
2037 static wxString
MakeLabel(const char *classname
, const char *funcname
)
2039 wxString
label(classname
);
2040 if ( funcname
&& funcname
[0] == '\\' ) {
2041 // we may have some special TeX macro - so far only \destruct exists,
2042 // but may be later others will be added
2043 static const char *macros
[] = { "destruct" };
2044 static const char *replacement
[] = { "dtor" };
2047 for ( n
= 0; n
< WXSIZEOF(macros
); n
++ ) {
2048 if ( strncmp(funcname
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) {
2054 if ( n
== WXSIZEOF(macros
) ) {
2055 wxLogWarning("unknown function name '%s' - leaving as is.",
2059 funcname
= replacement
[n
];
2064 // special treatment for operatorXXX() stuff because the C operators
2065 // are not valid in LaTeX labels
2067 if ( wxString(funcname
).StartsWith("operator", &oper
) ) {
2068 label
<< "operator";
2081 for ( n
= 0; n
< WXSIZEOF(operatorNames
); n
++ ) {
2082 if ( oper
== operatorNames
[n
].oper
) {
2083 label
<< operatorNames
[n
].name
;
2089 if ( n
== WXSIZEOF(operatorNames
) ) {
2090 wxLogWarning("unknown operator '%s' - making dummy label.",
2096 else // simply use the func name
2107 static wxString
MakeHelpref(const char *argument
)
2110 helpref
<< "\\helpref{" << argument
<< "}{" << MakeLabel(argument
) << '}';
2115 static void TeXFilter(wxString
* str
)
2117 // TeX special which can be quoted (don't include backslash nor braces as
2119 static wxRegEx
reNonSpecialSpecials("[#$%&_]"),
2123 reNonSpecialSpecials
.ReplaceAll(str
, "\\\\\\0");
2125 // can't quote these ones as they produce accents when preceded by
2126 // backslash, so put them inside verb
2127 reAccents
.ReplaceAll(str
, "\\\\verb|\\0|");
2130 static void TeXUnfilter(wxString
* str
)
2132 // FIXME may be done much more quickly
2137 static wxRegEx
reNonSpecialSpecials("\\\\([#$%&_{}])"),
2138 reAccents("\\\\verb\\|([~^])\\|");
2140 reNonSpecialSpecials
.ReplaceAll(str
, "\\1");
2141 reAccents
.ReplaceAll(str
, "\\1");
2144 static wxString
GetAllComments(const spContext
& ctx
)
2147 const MCommentListT
& commentsList
= ctx
.GetCommentList();
2148 for ( MCommentListT::const_iterator i
= commentsList
.begin();
2149 i
!= commentsList
.end();
2151 wxString comment
= (*i
)->GetText();
2153 // don't take comments like "// ----------" &c
2154 comment
.Trim(FALSE
);
2156 comment
== wxString(comment
[0u], comment
.length() - 1) + '\n' )
2159 comments
<< comment
;
2165 static const char *GetCurrentTime(const char *timeFormat
)
2167 static char s_timeBuffer
[128];
2172 ptmNow
= localtime(&timeNow
);
2174 strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
);
2176 return s_timeBuffer
;
2179 static const wxString
GetVersionString()
2181 wxString version
= "$Revision$";
2182 wxRegEx("^\\$Revision$$").ReplaceFirst(&version
, "\\1");
2188 Revision 1.27 2003/10/13 17:21:30 MBN
2191 Revision 1.26 2003/09/29 15:18:35 MBN
2192 (Blind) compilation fix for Sun compiler.
2194 Revision 1.25 2003/09/03 17:39:27 MBN
2197 Revision 1.24 2003/08/13 22:59:37 VZ
2200 Revision 1.23 2003/06/13 17:05:43 VZ
2201 quote '|' inside regexes (fixes dump mode); fixed crash due to strange HelpGenApp code
2203 Revision 1.22 2002/01/21 21:18:50 JS
2204 Now adds 'include file' heading
2206 Revision 1.21 2002/01/04 11:06:09 JS
2207 Fixed missing membersections bug and also bug with functions not being written
2210 Revision 1.20 2002/01/03 14:23:33 JS
2211 Added code to make it not duplicate membersections for overloaded functions
2213 Revision 1.19 2002/01/03 13:34:12 JS
2214 Added FlushAll to CloseClass, otherwise text was only flushed right at the end,
2215 and appeared in one file.
2217 Revision 1.18 2002/01/03 12:02:47 JS
2218 Added main() and corrected VC++ project settings
2220 Revision 1.17 2001/11/30 21:43:35 VZ
2221 now the methods are sorted in the correct order in the generated docs
2223 Revision 1.16 2001/11/28 19:27:33 VZ
2224 HelpGen doesn't work in GUI mode
2226 Revision 1.15 2001/11/22 21:59:58 GD
2227 use "..." instead of <...> for wx headers
2229 Revision 1.14 2001/07/19 13:51:29 VZ
2230 fixes to version string
2232 Revision 1.13 2001/07/19 13:44:57 VZ
2233 1. compilation fixes
2234 2. don't quote special characters inside verbatim environment
2236 Revision 1.12 2000/10/09 13:53:33 juliansmart
2238 Doc corrections; added HelpGen project files
2240 Revision 1.11 2000/07/15 19:50:42 cvsuser
2243 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
2244 don't trasnform output dir name to lower case
2246 Revision 1.10 2000/03/11 10:05:23 VS
2247 now compiles with wxBase
2249 Revision 1.9 2000/01/16 13:25:21 VS
2250 compilation fixes (gcc)
2252 Revision 1.8 1999/09/13 14:29:39 JS
2254 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2255 into src for simplicity; added VC++ 5 project file
2257 Revision 1.7 1999/02/21 22:32:32 VZ
2258 1. more C++ parser fixes - now it almost parses wx/string.h
2259 a) #if/#ifdef/#else (very) limited support
2260 b) param type fix - now indirection chars are correctly handled
2261 c) class/struct/union distinction
2262 d) public/private fixes
2263 e) Dump() function added - very useful for debugging
2265 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2266 by default, and this option switches it on)
2268 Revision 1.6 1999/02/20 23:00:26 VZ
2269 1. new 'diff' mode which seems to work
2270 2. output files are not overwritten in 'dmup' mode
2271 3. fixes for better handling of const functions and operators
2272 ----------------------------
2274 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2275 1. Parser improvements
2276 a) const and virtual methods are parsed correctly (not static yet)
2277 b) "const" which is part of the return type is not swallowed
2279 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2280 "//---------" kind comments discarded now.
2281 ----------------------------
2283 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2285 some tweaks to HelpGen
2286 ----------------------------
2288 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2290 HelpGen starting to compile with VC++
2291 ----------------------------
2293 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2295 supports typedefs, generates "See also:" and adds "virtual " for virtual
2297 ----------------------------
2299 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2301 HelpGen is a prototype of the tool for automatic generation of the .tex files
2302 for wxWindows documentation from C++ headers
2305 /* vi: set tw=80 et ts=4 sw=4: */