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"
64 // C++ parsing classes
71 // argh, Windows defines this
76 // -----------------------------------------------------------------------------
78 // -----------------------------------------------------------------------------
80 // return the label for the given function name (i.e. argument of \label)
81 static wxString
MakeLabel(const char *classname
, const char *funcname
= NULL
);
83 // return the whole \helpref{arg}{arg_label} string
84 static wxString
MakeHelpref(const char *argument
);
86 // [un]quote special TeX characters (in place)
87 static void TeXFilter(wxString
* str
);
88 static void TeXUnfilter(wxString
* str
); // also trims spaces
90 // get all comments associated with this context
91 static wxString
GetAllComments(const spContext
& ctx
);
93 // get the string with current time (returns pointer to static buffer)
94 // timeFormat is used for the call of strftime(3)
95 static const char *GetCurrentTime(const char *timeFormat
);
97 // get the string containing the program version
98 static const wxString
GetVersionString();
100 // -----------------------------------------------------------------------------
102 // -----------------------------------------------------------------------------
104 // a function documentation entry
105 struct FunctionDocEntry
107 FunctionDocEntry(const wxString
& name_
, const wxString
& text_
)
108 : name(name_
), text(text_
) { }
113 // the function doc text
117 static int Compare(FunctionDocEntry
**pp1
, FunctionDocEntry
**pp2
)
119 // the methods should appear in the following order: ctors, dtor, all
120 // the rest in the alphabetical order
121 bool isCtor1
= (*pp1
)->name
== classname
;
122 bool isCtor2
= (*pp2
)->name
== classname
;
126 // we don't order the ctors because we don't know how to do it
130 // ctor comes before non-ctor
135 // non-ctor must come after ctor
139 wxString dtorname
= wxString('~') + classname
;
141 // there is only one dtor, so the logic here is simpler
142 if ( (*pp1
)->name
== dtorname
) {
145 else if ( (*pp2
)->name
== dtorname
) {
149 // two normal methods
150 return strcmp((*pp1
)->name
, (*pp2
)->name
);
154 static wxString classname
;
157 wxString
FunctionDocEntry::classname
;
159 WX_DECLARE_OBJARRAY(FunctionDocEntry
, FunctionDocEntries
);
161 #include "wx/arrimpl.cpp"
163 WX_DEFINE_OBJARRAY(FunctionDocEntries
);
165 // add a function which sanitazes the string before writing it to the file and
166 // also capable of delaying output and sorting it before really writing it to
167 // the file (done from FlushAll())
168 class wxTeXFile
: public wxFile
173 // write a string to file verbatim (should only be used for the strings
174 // inside verbatim environment)
175 void WriteVerbatim(const wxString
& s
)
180 // write a string quoting TeX specials in it
181 void WriteTeX(const wxString
& s
)
189 // do write everything to file
192 if ( m_text
.empty() )
195 if ( !Write(m_text
) ) {
196 wxLogError("Failed to output generated documentation.");
207 wxTeXFile(const wxTeXFile
&);
208 wxTeXFile
& operator=(const wxTeXFile
&);
213 // helper class which manages the classes and function names to ignore for
214 // the documentation purposes (used by both HelpGenVisitor and DocManager)
215 class IgnoreNamesHandler
218 IgnoreNamesHandler() : m_ignore(CompareIgnoreListEntries
) { }
219 ~IgnoreNamesHandler() { WX_CLEAR_ARRAY(m_ignore
); }
221 // load file with classes/functions to ignore (add them to the names we
223 bool AddNamesFromFile(const wxString
& filename
);
225 // return TRUE if we ignore this function
226 bool IgnoreMethod(const wxString
& classname
,
227 const wxString
& funcname
) const
229 if ( IgnoreClass(classname
) )
232 IgnoreListEntry
ignore(classname
, funcname
);
234 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
237 // return TRUE if we ignore this class entirely
238 bool IgnoreClass(const wxString
& classname
) const
240 IgnoreListEntry
ignore(classname
, "");
242 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
246 struct IgnoreListEntry
248 IgnoreListEntry(const wxString
& classname
,
249 const wxString
& funcname
)
250 : m_classname(classname
), m_funcname(funcname
)
254 wxString m_classname
;
255 wxString m_funcname
; // if empty, ignore class entirely
258 static int CompareIgnoreListEntries(IgnoreListEntry
*first
,
259 IgnoreListEntry
*second
);
261 // for efficiency, let's sort it
262 WX_DEFINE_SORTED_ARRAY(IgnoreListEntry
*, ArrayNamesToIgnore
);
264 ArrayNamesToIgnore m_ignore
;
267 IgnoreNamesHandler(const IgnoreNamesHandler
&);
268 IgnoreNamesHandler
& operator=(const IgnoreNamesHandler
&);
271 // visitor implementation which writes all collected data to a .tex file
272 class HelpGenVisitor
: public spVisitor
276 HelpGenVisitor(const wxString
& directoryOut
, bool overwrite
);
278 virtual void VisitFile( spFile
& fl
);
279 virtual void VisitClass( spClass
& cl
);
280 virtual void VisitEnumeration( spEnumeration
& en
);
281 virtual void VisitTypeDef( spTypeDef
& td
);
282 virtual void VisitPreprocessorLine( spPreprocessorLine
& pd
);
283 virtual void VisitAttribute( spAttribute
& attr
);
284 virtual void VisitOperation( spOperation
& op
);
285 virtual void VisitParameter( spParameter
& param
);
289 // get our `ignore' object
290 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
292 // shut up g++ warning (ain't it stupid?)
293 virtual ~HelpGenVisitor() { }
296 // (re)initialize the state
299 // insert documentation for enums/typedefs coming immediately before the
300 // class declaration into the class documentation
301 void InsertTypedefDocs();
302 void InsertEnumDocs();
304 // write the headers for corresponding sections (only once)
305 void InsertDataStructuresHeader();
306 void InsertMethodsHeader();
308 // terminate the function documentation if it was started
309 void CloseFunction();
311 // write out all function docs when there are no more left in this class
312 // after sorting them in alphabetical order
315 wxString m_directoryOut
, // directory for the output
316 m_fileHeader
; // name of the .h file we parse
317 bool m_overwrite
; // overwrite existing files?
318 wxTeXFile m_file
; // file we're writing to now
321 bool m_inClass
, // TRUE after file successfully opened
322 m_inTypesSection
, // enums & typedefs go there
323 m_inMethodSection
, // functions go here
324 m_isFirstParam
; // first parameter of current function?
326 // non empty while parsing a class
327 wxString m_classname
;
329 // these are only non-empty while parsing a method:
330 wxString m_funcName
, // the function name
331 m_textFunc
; // the function doc text
333 // the array containing the documentation entries for the functions in the
334 // class currently being parsed
335 FunctionDocEntries m_arrayFuncDocs
;
337 // holders for "saved" documentation
338 wxString m_textStoredTypedefs
,
339 m_textStoredFunctionComment
;
341 // for enums we have to use an array as we can't intermix the normal text
342 // and the text inside verbatim environment
343 wxArrayString m_storedEnums
,
346 // headers included by this file
347 wxArrayString m_headers
;
349 // ignore handler: tells us which classes to ignore for doc generation
351 IgnoreNamesHandler m_ignoreNames
;
354 HelpGenVisitor(const HelpGenVisitor
&);
355 HelpGenVisitor
& operator=(const HelpGenVisitor
&);
358 // documentation manager - a class which parses TeX files and remembers the
359 // functions documented in them and can later compare them with all functions
360 // found under ctxTop by C++ parser
364 DocManager(bool checkParamNames
);
367 // returns FALSE on failure
368 bool ParseTeXFile(const wxString
& filename
);
370 // returns FALSE if there were any differences
371 bool DumpDifferences(spContext
*ctxTop
) const;
373 // get our `ignore' object
374 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
380 // returns the length of 'match' if the string 'str' starts with it or 0
382 static size_t TryMatch(const char *str
, const char *match
);
384 // skip spaces: returns pointer to first non space character (also
385 // updates the value of m_line)
386 const char *SkipSpaces(const char *p
)
388 while ( isspace(*p
) ) {
396 // skips characters until the next 'c' in '*pp' unless it ends before in
397 // which case FALSE is returned and pp points to '\0', otherwise TRUE is
398 // returned and pp points to 'c'
399 bool SkipUntil(const char **pp
, char c
);
401 // the same as SkipUntil() but only spaces are skipped: on first non space
402 // character different from 'c' the function stops and returns FALSE
403 bool SkipSpaceUntil(const char **pp
, char c
);
405 // extract the string between {} and modify '*pp' to point at the
406 // character immediately after the closing '}'. The returned string is empty
408 wxString
ExtractStringBetweenBraces(const char **pp
);
410 // the current file and line while we're in ParseTeXFile (for error
415 // functions and classes to ignore during diff
416 // -------------------------------------------
418 IgnoreNamesHandler m_ignoreNames
;
420 // information about all functions documented in the TeX file(s)
421 // -------------------------------------------------------------
423 // info about a type: for now stored as text string, but must be parsed
424 // further later (to know that "char *" == "char []" - TODO)
428 TypeInfo(const wxString
& type
) : m_type(type
) { }
430 bool operator==(const wxString
& type
) const { return m_type
== type
; }
431 bool operator!=(const wxString
& type
) const { return m_type
!= type
; }
433 const wxString
& GetName() const { return m_type
; }
439 // info abotu a function parameter
443 ParamInfo(const wxString
& type
,
444 const wxString
& name
,
445 const wxString
& value
)
446 : m_type(type
), m_name(name
), m_value(value
)
450 const TypeInfo
& GetType() const { return m_type
; }
451 const wxString
& GetName() const { return m_name
; }
452 const wxString
& GetDefValue() const { return m_value
; }
455 TypeInfo m_type
; // type of parameter
456 wxString m_name
; // name
457 wxString m_value
; // default value
460 WX_DEFINE_ARRAY(ParamInfo
*, ArrayParamInfo
);
462 // info about a function
475 MethodInfo(const wxString
& type
,
476 const wxString
& name
,
477 const ArrayParamInfo
& params
)
478 : m_typeRet(type
), m_name(name
), m_params(params
)
483 void SetFlag(MethodFlags flag
) { m_flags
|= flag
; }
485 const TypeInfo
& GetType() const { return m_typeRet
; }
486 const wxString
& GetName() const { return m_name
; }
487 const ParamInfo
& GetParam(size_t n
) const { return *(m_params
[n
]); }
488 size_t GetParamCount() const { return m_params
.GetCount(); }
490 bool HasFlag(MethodFlags flag
) const { return (m_flags
& flag
) != 0; }
492 ~MethodInfo() { WX_CLEAR_ARRAY(m_params
); }
495 TypeInfo m_typeRet
; // return type
497 int m_flags
; // bit mask of the value from the enum above
499 ArrayParamInfo m_params
;
502 WX_DEFINE_ARRAY(MethodInfo
*, ArrayMethodInfo
);
503 WX_DEFINE_ARRAY(ArrayMethodInfo
*, ArrayMethodInfos
);
505 // first array contains the names of all classes we found, the second has a
506 // pointer to the array of methods of the given class at the same index as
507 // the class name appears in m_classes
508 wxArrayString m_classes
;
509 ArrayMethodInfos m_methods
;
511 // are we checking parameter names?
512 bool m_checkParamNames
;
515 DocManager(const DocManager
&);
516 DocManager
& operator=(const DocManager
&);
519 // =============================================================================
521 // =============================================================================
523 static char **g_argv
= NULL
;
525 // this function never returns
528 wxString prog
= g_argv
[0];
529 wxString basename
= prog
.AfterLast('/');
532 basename
= prog
.AfterLast('\\');
538 "usage: %s [global options] <mode> [mode options] <files...>\n"
540 " where global options are:\n"
543 " -H give this usage message\n"
544 " -V print the version info\n"
545 " -i file file with classes/function to ignore\n"
547 " where mode is one of: dump, diff\n"
549 " dump means generate .tex files for TeX2RTF converter from specified\n"
550 " headers files, mode options are:\n"
551 " -f overwrite existing files\n"
552 " -o outdir directory for generated files\n"
554 " diff means compare the set of methods documented .tex file with the\n"
555 " methods declared in the header:\n"
556 " %s diff <file.h> <files.tex...>.\n"
557 " mode specific options are:\n"
558 " -p do check parameter names (not done by default)\n"
559 "\n", basename
.c_str(), basename
.c_str());
564 int main(int argc
, char **argv
)
568 wxInitializer initializer
;
571 fprintf(stderr
, "Failed to initialize the wxWindows library, aborting.");
587 wxArrayString filesH
, filesTeX
;
588 wxString directoryOut
, // directory for 'dmup' output
589 ignoreFile
; // file with classes/functions to ignore
590 bool overwrite
= FALSE
, // overwrite existing files during 'dump'?
591 paramNames
= FALSE
; // check param names during 'diff'?
593 for ( int current
= 1; current
< argc
; current
++ ) {
594 // all options have one letter
595 if ( argv
[current
][0] == '-' ) {
596 if ( argv
[current
][2] == '\0' ) {
597 switch ( argv
[current
][1] ) {
600 wxLog::GetActiveTarget()->SetVerbose();
605 wxLog::GetActiveTarget()->SetVerbose(FALSE
);
615 wxLogMessage("HelpGen version %s\n"
616 "(c) 1999-2001 Vadim Zeitlin\n",
617 GetVersionString().c_str());
622 if ( current
>= argc
) {
623 wxLogError("-i option requires an argument.");
628 ignoreFile
= argv
[current
];
632 if ( mode
!= Mode_Diff
) {
633 wxLogError("-p is only valid with diff.");
642 if ( mode
!= Mode_Dump
) {
643 wxLogError("-f is only valid with dump.");
652 if ( mode
!= Mode_Dump
) {
653 wxLogError("-o is only valid with dump.");
659 if ( current
>= argc
) {
660 wxLogError("-o option requires an argument.");
665 directoryOut
= argv
[current
];
666 if ( !!directoryOut
) {
667 // terminate with a '/' if it doesn't have it
668 switch ( directoryOut
.Last() ) {
679 //else: it's empty, do nothing
684 wxLogError("unknown option '%s'", argv
[current
]);
689 wxLogError("only one letter options are allowed, not '%s'.",
693 // only get here after a break from switch or from else branch of if
698 if ( mode
== Mode_None
) {
699 if ( strcmp(argv
[current
], "diff") == 0 )
701 else if ( strcmp(argv
[current
], "dump") == 0 )
704 wxLogError("unknown mode '%s'.", argv
[current
]);
710 if ( mode
== Mode_Dump
|| filesH
.IsEmpty() ) {
711 filesH
.Add(argv
[current
]);
714 // 2nd files and further are TeX files in diff mode
715 wxASSERT( mode
== Mode_Diff
);
717 filesTeX
.Add(argv
[current
]);
723 // create a parser object and a visitor derivation
724 CJSourceParser parser
;
725 HelpGenVisitor
visitor(directoryOut
, overwrite
);
726 if ( !!ignoreFile
&& mode
== Mode_Dump
)
727 visitor
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
729 spContext
*ctxTop
= NULL
;
731 // parse all header files
732 size_t nFiles
= filesH
.GetCount();
733 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
734 wxString header
= filesH
[n
];
735 ctxTop
= parser
.ParseFile(header
);
737 wxLogWarning("Header file '%s' couldn't be processed.",
740 else if ( mode
== Mode_Dump
) {
741 ((spFile
*)ctxTop
)->mFileName
= header
;
742 visitor
.VisitAll(*ctxTop
);
749 #endif // __WXDEBUG__
752 // parse all TeX files
753 if ( mode
== Mode_Diff
) {
755 wxLogError("Can't complete diff.");
761 DocManager
docman(paramNames
);
763 size_t nFiles
= filesTeX
.GetCount();
764 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
765 wxString file
= filesTeX
[n
];
766 if ( !docman
.ParseTeXFile(file
) ) {
767 wxLogWarning("TeX file '%s' couldn't be processed.",
773 docman
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
775 docman
.DumpDifferences(ctxTop
);
781 // -----------------------------------------------------------------------------
782 // HelpGenVisitor implementation
783 // -----------------------------------------------------------------------------
785 HelpGenVisitor::HelpGenVisitor(const wxString
& directoryOut
,
787 : m_directoryOut(directoryOut
)
789 m_overwrite
= overwrite
;
794 void HelpGenVisitor::Reset()
798 m_inMethodSection
= FALSE
;
803 m_textStoredTypedefs
=
804 m_textStoredFunctionComment
= "";
806 m_arrayFuncDocs
.Empty();
808 m_storedEnums
.Empty();
809 m_storedEnumsVerb
.Empty();
813 void HelpGenVisitor::InsertTypedefDocs()
815 m_file
.WriteTeX(m_textStoredTypedefs
);
816 m_textStoredTypedefs
.Empty();
819 void HelpGenVisitor::InsertEnumDocs()
821 size_t count
= m_storedEnums
.GetCount();
822 for ( size_t n
= 0; n
< count
; n
++ )
824 m_file
.WriteTeX(m_storedEnums
[n
]);
825 m_file
.WriteVerbatim(m_storedEnumsVerb
[n
] + '\n');
828 m_storedEnums
.Empty();
829 m_storedEnumsVerb
.Empty();
832 void HelpGenVisitor::InsertDataStructuresHeader()
834 if ( !m_inTypesSection
) {
835 m_inTypesSection
= TRUE
;
837 m_file
.WriteVerbatim("\\wxheading{Data structures}\n\n");
841 void HelpGenVisitor::InsertMethodsHeader()
843 if ( !m_inMethodSection
) {
844 m_inMethodSection
= TRUE
;
846 m_file
.WriteVerbatim( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
850 void HelpGenVisitor::CloseFunction()
852 if ( !m_funcName
.empty() ) {
853 if ( m_isFirstParam
) {
855 m_textFunc
<< "\\void";
858 m_textFunc
<< "}\n\n";
860 if ( !m_textStoredFunctionComment
.IsEmpty() ) {
861 m_textFunc
<< m_textStoredFunctionComment
<< '\n';
864 m_arrayFuncDocs
.Add(new FunctionDocEntry(m_funcName
, m_textFunc
));
870 void HelpGenVisitor::CloseClass()
875 size_t count
= m_arrayFuncDocs
.GetCount();
878 FunctionDocEntry::classname
= m_classname
;
880 m_arrayFuncDocs
.Sort(FunctionDocEntry::Compare
);
882 // Now examine each first line and if it's been seen, cut it
883 // off (it's a duplicate \membersection)
884 wxHashTable
membersections(wxKEY_STRING
);
886 for ( n
= 0; n
< count
; n
++ )
888 wxString
section(m_arrayFuncDocs
[n
].text
);
890 // Strip leading whitespace
891 int pos
= section
.Find("\\membersection");
894 section
= section
.Mid(pos
);
897 wxString
ms(section
.BeforeFirst(wxT('\n')));
898 if (membersections
.Get(ms
))
900 m_arrayFuncDocs
[n
].text
= section
.AfterFirst(wxT('\n'));
904 membersections
.Put(ms
, & membersections
);
908 for ( n
= 0; n
< count
; n
++ ) {
909 m_file
.WriteTeX(m_arrayFuncDocs
[n
].text
);
912 m_arrayFuncDocs
.Empty();
921 void HelpGenVisitor::EndVisit()
927 m_fileHeader
.Empty();
930 if (m_file
.IsOpened())
936 wxLogVerbose("%s: finished generating for the current file.",
937 GetCurrentTime("%H:%M:%S"));
940 void HelpGenVisitor::VisitFile( spFile
& file
)
942 m_fileHeader
= file
.mFileName
;
943 wxLogVerbose("%s: started generating docs for classes from file '%s'...",
944 GetCurrentTime("%H:%M:%S"), m_fileHeader
.c_str());
947 void HelpGenVisitor::VisitClass( spClass
& cl
)
951 if (m_file
.IsOpened())
957 wxString name
= cl
.GetName();
959 if ( m_ignoreNames
.IgnoreClass(name
) ) {
960 wxLogVerbose("Skipping ignored class '%s'.", name
.c_str());
965 // the file name is built from the class name by removing the leading "wx"
966 // if any and converting it to the lower case
968 if ( name(0, 2) == "wx" ) {
969 filename
<< name
.c_str() + 2;
975 filename
.MakeLower();
977 filename
.Prepend(m_directoryOut
);
979 if ( !m_overwrite
&& wxFile::Exists(filename
) ) {
980 wxLogError("Won't overwrite existing file '%s' - please use '-f'.",
986 m_inClass
= m_file
.Open(filename
, wxFile::write
);
988 wxLogError("Can't generate documentation for the class '%s'.",
995 m_inTypesSection
= FALSE
;
997 wxLogInfo("Created new file '%s' for class '%s'.",
998 filename
.c_str(), name
.c_str());
1000 // write out the header
1002 header
.Printf("%%\n"
1003 "%% automatically generated by HelpGen %s from\n"
1008 "\\section{\\class{%s}}\\label{%s}\n\n",
1009 GetVersionString().c_str(),
1010 m_fileHeader
.c_str(),
1011 GetCurrentTime("%d/%b/%y %H:%M:%S"),
1013 wxString(name
).MakeLower().c_str());
1015 m_file
.WriteVerbatim(header
);
1017 // the entire text we're writing to file
1020 // if the header includes other headers they must be related to it... try to
1021 // automatically generate the "See also" clause
1022 if ( !m_headers
.IsEmpty() ) {
1023 // correspondence between wxWindows headers and class names
1024 static const char *headers
[] = {
1033 // NULL here means not to insert anything in "See also" for the
1034 // corresponding header
1035 static const char *classes
[] = {
1044 wxASSERT_MSG( WXSIZEOF(headers
) == WXSIZEOF(classes
),
1045 "arrays must be in sync!" );
1047 wxArrayInt interestingClasses
;
1049 size_t count
= m_headers
.Count(), index
;
1050 for ( size_t n
= 0; n
< count
; n
++ ) {
1051 wxString baseHeaderName
= m_headers
[n
].Before('.');
1052 if ( baseHeaderName(0, 3) != "wx/" )
1055 baseHeaderName
.erase(0, 3);
1056 for ( index
= 0; index
< WXSIZEOF(headers
); index
++ ) {
1057 if ( Stricmp(baseHeaderName
, headers
[index
]) == 0 )
1061 if ( (index
< WXSIZEOF(headers
)) && classes
[index
] ) {
1062 // interesting header
1063 interestingClasses
.Add(index
);
1067 if ( !interestingClasses
.IsEmpty() ) {
1068 // do generate "See also" clause
1069 totalText
<< "\\wxheading{See also:}\n\n";
1071 count
= interestingClasses
.Count();
1072 for ( index
= 0; index
< count
; index
++ ) {
1076 totalText
<< MakeHelpref(classes
[interestingClasses
[index
]]);
1079 totalText
<< "\n\n";
1083 // the comment before the class generally explains what is it for so put it
1084 // in place of the class description
1085 if ( cl
.HasComments() ) {
1086 wxString comment
= GetAllComments(cl
);
1088 totalText
<< '\n' << comment
<< '\n';
1091 // derived from section
1092 wxString derived
= "\\wxheading{Derived from}\n\n";
1094 const StrListT
& baseClasses
= cl
.mSuperClassNames
;
1095 if ( baseClasses
.size() == 0 ) {
1096 derived
<< "No base class";
1100 for ( StrListT::const_iterator i
= baseClasses
.begin();
1101 i
!= baseClasses
.end();
1104 // separate from the previous one
1105 derived
<< "\\\\\n";
1111 wxString baseclass
= *i
;
1112 derived
<< "\\helpref{" << baseclass
<< "}";
1113 derived
<< "{" << baseclass
.MakeLower() << "}";
1116 totalText
<< derived
<< "\n\n";
1118 // include file section
1119 wxString includeFile
= "\\wxheading{Include files}\n\n";
1120 includeFile
<< "<" << m_fileHeader
<< ">";
1122 totalText
<< includeFile
<< "\n\n";
1124 // write all this to file
1125 m_file
.WriteTeX(totalText
);
1127 // if there were any enums/typedefs before, insert their documentation now
1128 InsertDataStructuresHeader();
1129 InsertTypedefDocs();
1135 void HelpGenVisitor::VisitEnumeration( spEnumeration
& en
)
1139 if ( m_inMethodSection
) {
1140 // FIXME that's a bug, but tell the user aboit it nevertheless... we
1141 // should be smart enough to process even the enums which come after the
1143 wxLogWarning("enum '%s' ignored, please put it before the class "
1144 "methods.", en
.GetName().c_str());
1148 // simply copy the enum text in the docs
1149 wxString enumeration
= GetAllComments(en
),
1152 enumerationVerb
<< "\\begin{verbatim}\n"
1154 << "\n\\end{verbatim}\n";
1156 // remember for later use if we're not inside a class yet
1158 m_storedEnums
.Add(enumeration
);
1159 m_storedEnumsVerb
.Add(enumerationVerb
);
1162 // write the header for this section if not done yet
1163 InsertDataStructuresHeader();
1165 m_file
.WriteTeX(enumeration
);
1166 m_file
.WriteVerbatim(enumerationVerb
);
1167 m_file
.WriteVerbatim('\n');
1171 void HelpGenVisitor::VisitTypeDef( spTypeDef
& td
)
1175 if ( m_inMethodSection
) {
1176 // FIXME that's a bug, but tell the user aboit it nevertheless...
1177 wxLogWarning("typedef '%s' ignored, please put it before the class "
1178 "methods.", td
.GetName().c_str());
1182 wxString typedefdoc
;
1183 typedefdoc
<< "{\\small \\begin{verbatim}\n"
1184 << "typedef " << td
.mOriginalType
<< ' ' << td
.GetName()
1185 << "\n\\end{verbatim}}\n"
1186 << GetAllComments(td
);
1188 // remember for later use if we're not inside a class yet
1190 if ( !m_textStoredTypedefs
.IsEmpty() ) {
1191 m_textStoredTypedefs
<< '\n';
1194 m_textStoredTypedefs
<< typedefdoc
;
1197 // write the header for this section if not done yet
1198 InsertDataStructuresHeader();
1201 m_file
.WriteTeX(typedefdoc
);
1205 void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine
& pd
)
1207 switch ( pd
.GetStatementType() ) {
1208 case SP_PREP_DEF_INCLUDE_FILE
:
1209 m_headers
.Add(pd
.CPP_GetIncludedFileNeme());
1212 case SP_PREP_DEF_DEFINE_SYMBOL
:
1213 // TODO decide if it's a constant and document it if it is
1218 void HelpGenVisitor::VisitAttribute( spAttribute
& attr
)
1222 // only document the public member variables
1223 if ( !m_inClass
|| !attr
.IsPublic() )
1226 wxLogWarning("Ignoring member variable '%s'.", attr
.GetName().c_str());
1229 void HelpGenVisitor::VisitOperation( spOperation
& op
)
1234 // we don't generate docs right now - either we ignore this class
1235 // entirely or we couldn't open the file
1239 if ( !op
.IsInClass() ) {
1240 // TODO document global functions
1241 wxLogWarning("skipped global function '%s'.", op
.GetName().c_str());
1246 if ( op
.mVisibility
== SP_VIS_PRIVATE
) {
1247 // FIXME should we document protected functions?
1251 m_classname
= op
.GetClass().GetName();
1252 wxString funcname
= op
.GetName();
1254 if ( m_ignoreNames
.IgnoreMethod(m_classname
, funcname
) ) {
1255 wxLogVerbose("Skipping ignored '%s::%s'.",
1256 m_classname
.c_str(), funcname
.c_str());
1261 InsertMethodsHeader();
1264 m_funcName
= funcname
;
1265 m_isFirstParam
= TRUE
;
1267 m_textStoredFunctionComment
= GetAllComments(op
);
1269 // start function documentation
1272 // check for the special case of dtor
1274 if ( (funcname
[0] == '~') && (m_classname
== funcname
.c_str() + 1) ) {
1275 dtor
.Printf("\\destruct{%s}", m_classname
.c_str());
1279 m_textFunc
.Printf("\n"
1280 "\\membersection{%s::%s}\\label{%s}\n",
1281 m_classname
.c_str(), funcname
.c_str(),
1282 MakeLabel(m_classname
, funcname
).c_str());
1286 "\\%sfunc{%s%s}{%s}{",
1287 op
.mIsConstant
? "const" : "",
1288 op
.mIsVirtual
? "virtual " : "",
1289 op
.mRetType
.c_str(),
1294 void HelpGenVisitor::VisitParameter( spParameter
& param
)
1296 if ( m_funcName
.empty() )
1299 if ( m_isFirstParam
) {
1300 m_isFirstParam
= FALSE
;
1306 m_textFunc
<< "\\param{" << param
.mType
<< " }{" << param
.GetName();
1307 wxString defvalue
= param
.mInitVal
;
1308 if ( !defvalue
.IsEmpty() ) {
1309 m_textFunc
<< " = " << defvalue
;
1315 // ---------------------------------------------------------------------------
1317 // ---------------------------------------------------------------------------
1319 DocManager::DocManager(bool checkParamNames
)
1321 m_checkParamNames
= checkParamNames
;
1324 size_t DocManager::TryMatch(const char *str
, const char *match
)
1326 size_t lenMatch
= 0;
1327 while ( str
[lenMatch
] == match
[lenMatch
] ) {
1330 if ( match
[lenMatch
] == '\0' )
1337 bool DocManager::SkipUntil(const char **pp
, char c
)
1339 const char *p
= *pp
;
1355 bool DocManager::SkipSpaceUntil(const char **pp
, char c
)
1357 const char *p
= *pp
;
1359 if ( !isspace(*p
) || *p
== '\0' )
1373 wxString
DocManager::ExtractStringBetweenBraces(const char **pp
)
1377 if ( !SkipSpaceUntil(pp
, '{') ) {
1378 wxLogWarning("file %s(%d): '{' expected after '\\param'",
1379 m_filename
.c_str(), m_line
);
1383 const char *startParam
= ++*pp
; // skip '{'
1385 if ( !SkipUntil(pp
, '}') ) {
1386 wxLogWarning("file %s(%d): '}' expected after '\\param'",
1387 m_filename
.c_str(), m_line
);
1390 result
= wxString(startParam
, (*pp
)++ - startParam
);
1397 bool DocManager::ParseTeXFile(const wxString
& filename
)
1399 m_filename
= filename
;
1401 wxFile
file(m_filename
, wxFile::read
);
1402 if ( !file
.IsOpened() )
1405 off_t len
= file
.Length();
1406 if ( len
== wxInvalidOffset
)
1409 char *buf
= new char[len
+ 1];
1412 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1418 // reinit everything
1421 wxLogVerbose("%s: starting to parse doc file '%s'.",
1422 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1424 // the name of the class from the last "\membersection" command: we assume
1425 // that the following "\func" or "\constfunc" always documents a method of
1426 // this class (and it should always be like that in wxWindows documentation)
1429 for ( const char *current
= buf
; current
- buf
< len
; current
++ ) {
1430 // FIXME parsing is awfully inefficient
1432 if ( *current
== '%' ) {
1433 // comment, skip until the end of line
1435 SkipUntil(¤t
, '\n');
1440 // all the command we're interested in start with '\\'
1441 while ( *current
!= '\\' && *current
!= '\0' ) {
1442 if ( *current
++ == '\n' )
1446 if ( *current
== '\0' ) {
1447 // no more TeX commands left
1451 current
++; // skip '\\'
1459 } foundCommand
= Nothing
;
1461 size_t lenMatch
= TryMatch(current
, "func");
1463 foundCommand
= Func
;
1466 lenMatch
= TryMatch(current
, "constfunc");
1468 foundCommand
= ConstFunc
;
1470 lenMatch
= TryMatch(current
, "membersection");
1473 foundCommand
= MemberSect
;
1477 if ( foundCommand
== Nothing
)
1480 current
+= lenMatch
;
1482 if ( !SkipSpaceUntil(¤t
, '{') ) {
1483 wxLogWarning("file %s(%d): '{' expected after \\func, "
1484 "\\constfunc or \\membersection.",
1485 m_filename
.c_str(), m_line
);
1492 if ( foundCommand
== MemberSect
) {
1493 // what follows has the form <classname>::<funcname>
1494 const char *startClass
= current
;
1495 if ( !SkipUntil(¤t
, ':') || *(current
+ 1) != ':' ) {
1496 wxLogWarning("file %s(%d): '::' expected after "
1497 "\\membersection.", m_filename
.c_str(), m_line
);
1500 classname
= wxString(startClass
, current
- startClass
);
1501 TeXUnfilter(&classname
);
1507 // extract the return type
1508 const char *startRetType
= current
;
1510 if ( !SkipUntil(¤t
, '}') ) {
1511 wxLogWarning("file %s(%d): '}' expected after return type",
1512 m_filename
.c_str(), m_line
);
1517 wxString returnType
= wxString(startRetType
, current
- startRetType
);
1518 TeXUnfilter(&returnType
);
1521 if ( !SkipSpaceUntil(¤t
, '{') ) {
1522 wxLogWarning("file %s(%d): '{' expected after return type",
1523 m_filename
.c_str(), m_line
);
1529 const char *funcEnd
= current
;
1530 if ( !SkipUntil(&funcEnd
, '}') ) {
1531 wxLogWarning("file %s(%d): '}' expected after function name",
1532 m_filename
.c_str(), m_line
);
1537 wxString funcName
= wxString(current
, funcEnd
- current
);
1538 current
= funcEnd
+ 1;
1540 // trim spaces from both sides
1541 funcName
.Trim(FALSE
);
1542 funcName
.Trim(TRUE
);
1544 // special cases: '$...$' may be used for LaTeX inline math, remove the
1546 if ( funcName
.Find('$') != wxNOT_FOUND
) {
1548 for ( const char *p
= funcName
.c_str(); *p
!= '\0'; p
++ ) {
1549 if ( *p
!= '$' && !isspace(*p
) )
1556 // \destruct{foo} is really ~foo
1557 if ( funcName
[0u] == '\\' ) {
1558 size_t len
= strlen("\\destruct{");
1559 if ( funcName(0, len
) != "\\destruct{" ) {
1560 wxLogWarning("file %s(%d): \\destruct expected",
1561 m_filename
.c_str(), m_line
);
1566 funcName
.erase(0, len
);
1567 funcName
.Prepend('~');
1569 if ( !SkipSpaceUntil(¤t
, '}') ) {
1570 wxLogWarning("file %s(%d): '}' expected after destructor",
1571 m_filename
.c_str(), m_line
);
1576 funcEnd
++; // there is an extra '}' to count
1579 TeXUnfilter(&funcName
);
1582 current
= funcEnd
+ 1; // skip '}'
1583 if ( !SkipSpaceUntil(¤t
, '{') ||
1584 (current
++, !SkipSpaceUntil(¤t
, '\\')) ) {
1585 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1586 m_filename
.c_str(), m_line
);
1591 wxArrayString paramNames
, paramTypes
, paramValues
;
1593 bool isVararg
= FALSE
;
1595 current
++; // skip '\\'
1596 lenMatch
= TryMatch(current
, "void");
1598 lenMatch
= TryMatch(current
, "param");
1599 while ( lenMatch
&& (current
- buf
< len
) ) {
1600 current
+= lenMatch
;
1602 // now come {paramtype}{paramname}
1603 wxString paramType
= ExtractStringBetweenBraces(¤t
);
1604 if ( !!paramType
) {
1605 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1606 if ( !!paramText
) {
1607 // the param declaration may contain default value
1608 wxString paramName
= paramText
.BeforeFirst('='),
1609 paramValue
= paramText
.AfterFirst('=');
1611 // sanitize all strings
1612 TeXUnfilter(¶mValue
);
1613 TeXUnfilter(¶mName
);
1614 TeXUnfilter(¶mType
);
1616 paramValues
.Add(paramValue
);
1617 paramNames
.Add(paramName
);
1618 paramTypes
.Add(paramType
);
1623 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1624 if ( paramText
== "..." ) {
1628 wxLogWarning("Parameters of '%s::%s' are in "
1630 classname
.c_str(), funcName
.c_str());
1635 current
= SkipSpaces(current
);
1636 if ( *current
== ',' || *current
== '}' ) {
1637 current
= SkipSpaces(++current
);
1639 lenMatch
= TryMatch(current
, "\\param");
1642 wxLogWarning("file %s(%d): ',' or '}' expected after "
1643 "'\\param'", m_filename
.c_str(), m_line
);
1649 // if we got here there was no '\\void', so must have some params
1650 if ( paramNames
.IsEmpty() ) {
1651 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1652 m_filename
.c_str(), m_line
);
1658 // verbose diagnostic output
1660 size_t param
, paramCount
= paramNames
.GetCount();
1661 for ( param
= 0; param
< paramCount
; param
++ ) {
1666 paramsAll
<< paramTypes
[param
] << ' ' << paramNames
[param
];
1669 wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
1670 m_filename
.c_str(), m_line
,
1675 foundCommand
== ConstFunc
? " const" : "");
1677 // store the info about the just found function
1678 ArrayMethodInfo
*methods
;
1679 int index
= m_classes
.Index(classname
);
1680 if ( index
== wxNOT_FOUND
) {
1681 m_classes
.Add(classname
);
1683 methods
= new ArrayMethodInfo
;
1684 m_methods
.Add(methods
);
1687 methods
= m_methods
[(size_t)index
];
1690 ArrayParamInfo params
;
1691 for ( param
= 0; param
< paramCount
; param
++ ) {
1692 params
.Add(new ParamInfo(paramTypes
[param
],
1694 paramValues
[param
]));
1697 MethodInfo
*method
= new MethodInfo(returnType
, funcName
, params
);
1698 if ( foundCommand
== ConstFunc
)
1699 method
->SetFlag(MethodInfo::Const
);
1701 method
->SetFlag(MethodInfo::Vararg
);
1703 methods
->Add(method
);
1708 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1709 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1714 bool DocManager::DumpDifferences(spContext
*ctxTop
) const
1716 typedef MMemberListT::const_iterator MemberIndex
;
1718 bool foundDiff
= FALSE
;
1720 // flag telling us whether the given class was found at all in the header
1721 size_t nClass
, countClassesInDocs
= m_classes
.GetCount();
1722 bool *classExists
= new bool[countClassesInDocs
];
1723 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1724 classExists
[nClass
] = FALSE
;
1727 // ctxTop is normally an spFile
1728 wxASSERT( ctxTop
->GetContextType() == SP_CTX_FILE
);
1730 const MMemberListT
& classes
= ctxTop
->GetMembers();
1731 for ( MemberIndex i
= classes
.begin(); i
!= classes
.end(); i
++ ) {
1732 spContext
*ctx
= *i
;
1733 if ( ctx
->GetContextType() != SP_CTX_CLASS
) {
1734 // TODO process also global functions, macros, ...
1738 spClass
*ctxClass
= (spClass
*)ctx
;
1739 const wxString
& nameClass
= ctxClass
->mName
;
1740 int index
= m_classes
.Index(nameClass
);
1741 if ( index
== wxNOT_FOUND
) {
1742 if ( !m_ignoreNames
.IgnoreClass(nameClass
) ) {
1745 wxLogError("Class '%s' is not documented at all.",
1749 // it makes no sense to check for its functions
1753 classExists
[index
] = TRUE
;
1756 // array of method descriptions for this class
1757 const ArrayMethodInfo
& methods
= *(m_methods
[index
]);
1758 size_t nMethod
, countMethods
= methods
.GetCount();
1760 // flags telling if we already processed given function
1761 bool *methodExists
= new bool[countMethods
];
1762 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1763 methodExists
[nMethod
] = FALSE
;
1766 wxArrayString aOverloadedMethods
;
1768 const MMemberListT
& functions
= ctxClass
->GetMembers();
1769 for ( MemberIndex j
= functions
.begin(); j
!= functions
.end(); j
++ ) {
1771 if ( ctx
->GetContextType() != SP_CTX_OPERATION
)
1774 spOperation
*ctxMethod
= (spOperation
*)ctx
;
1775 const wxString
& nameMethod
= ctxMethod
->mName
;
1777 // find all functions with the same name
1778 wxArrayInt aMethodsWithSameName
;
1779 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1780 if ( methods
[nMethod
]->GetName() == nameMethod
)
1781 aMethodsWithSameName
.Add(nMethod
);
1784 if ( aMethodsWithSameName
.IsEmpty() && ctxMethod
->IsPublic() ) {
1785 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1788 wxLogError("'%s::%s' is not documented.",
1790 nameMethod
.c_str());
1793 // don't check params
1796 else if ( aMethodsWithSameName
.GetCount() == 1 ) {
1797 index
= (size_t)aMethodsWithSameName
[0u];
1798 methodExists
[index
] = TRUE
;
1800 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1803 if ( !ctxMethod
->IsPublic() ) {
1804 wxLogWarning("'%s::%s' is documented but not public.",
1806 nameMethod
.c_str());
1809 // check that the flags match
1810 const MethodInfo
& method
= *(methods
[index
]);
1812 bool isVirtual
= ctxMethod
->mIsVirtual
;
1813 if ( isVirtual
!= method
.HasFlag(MethodInfo::Virtual
) ) {
1814 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1818 isVirtual
? "not " : "");
1821 bool isConst
= ctxMethod
->mIsConstant
;
1822 if ( isConst
!= method
.HasFlag(MethodInfo::Const
) ) {
1823 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1827 isConst
? "not " : "");
1830 // check that the params match
1831 const MMemberListT
& params
= ctxMethod
->GetMembers();
1833 if ( params
.size() != method
.GetParamCount() ) {
1834 wxLogError("Incorrect number of parameters for '%s::%s' "
1835 "in the docs: should be %d instead of %d.",
1838 params
.size(), method
.GetParamCount());
1842 for ( MemberIndex k
= params
.begin();
1847 // what else can a function have?
1848 wxASSERT( ctx
->GetContextType() == SP_CTX_PARAMETER
);
1850 spParameter
*ctxParam
= (spParameter
*)ctx
;
1851 const ParamInfo
& param
= method
.GetParam(nParam
);
1852 if ( m_checkParamNames
&&
1853 (param
.GetName() != ctxParam
->mName
) ) {
1856 wxLogError("Parameter #%d of '%s::%s' should be "
1857 "'%s' and not '%s'.",
1861 ctxParam
->mName
.c_str(),
1862 param
.GetName().c_str());
1867 if ( param
.GetType() != ctxParam
->mType
) {
1870 wxLogError("Type of parameter '%s' of '%s::%s' "
1871 "should be '%s' and not '%s'.",
1872 ctxParam
->mName
.c_str(),
1875 ctxParam
->mType
.c_str(),
1876 param
.GetType().GetName().c_str());
1881 if ( param
.GetDefValue() != ctxParam
->mInitVal
) {
1882 wxLogWarning("Default value of parameter '%s' of "
1883 "'%s::%s' should be '%s' and not "
1885 ctxParam
->mName
.c_str(),
1888 ctxParam
->mInitVal
.c_str(),
1889 param
.GetDefValue().c_str());
1895 // TODO OVER add real support for overloaded methods
1897 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1900 if ( aOverloadedMethods
.Index(nameMethod
) == wxNOT_FOUND
) {
1901 // mark all methods with this name as existing
1902 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1903 if ( methods
[nMethod
]->GetName() == nameMethod
)
1904 methodExists
[nMethod
] = TRUE
;
1907 aOverloadedMethods
.Add(nameMethod
);
1909 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1910 "stupid to find the right match - skipping "
1911 "the param and flags checks.",
1913 nameMethod
.c_str());
1915 //else: warning already given
1919 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1920 if ( !methodExists
[nMethod
] ) {
1921 const wxString
& nameMethod
= methods
[nMethod
]->GetName();
1922 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1925 wxLogError("'%s::%s' is documented but doesn't exist.",
1927 nameMethod
.c_str());
1932 delete [] methodExists
;
1935 // check that all classes we found in the docs really exist
1936 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1937 if ( !classExists
[nClass
] ) {
1940 wxLogError("Class '%s' is documented but doesn't exist.",
1941 m_classes
[nClass
].c_str());
1945 delete [] classExists
;
1950 DocManager::~DocManager()
1952 WX_CLEAR_ARRAY(m_methods
);
1955 // ---------------------------------------------------------------------------
1956 // IgnoreNamesHandler implementation
1957 // ---------------------------------------------------------------------------
1959 int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry
*first
,
1960 IgnoreListEntry
*second
)
1962 // first compare the classes
1963 int rc
= first
->m_classname
.Cmp(second
->m_classname
);
1965 rc
= first
->m_funcname
.Cmp(second
->m_funcname
);
1970 bool IgnoreNamesHandler::AddNamesFromFile(const wxString
& filename
)
1972 wxFile
file(filename
, wxFile::read
);
1973 if ( !file
.IsOpened() )
1976 off_t len
= file
.Length();
1977 if ( len
== wxInvalidOffset
)
1980 char *buf
= new char[len
+ 1];
1983 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1990 for ( const char *current
= buf
; ; current
++ ) {
1992 // skip DOS line separator
1993 if ( *current
== '\r' )
1997 if ( *current
== '\n' || *current
== '\0' ) {
1998 if ( line
[0u] != '#' ) {
1999 if ( line
.Find(':') != wxNOT_FOUND
) {
2000 wxString classname
= line
.BeforeFirst(':'),
2001 funcname
= line
.AfterLast(':');
2002 m_ignore
.Add(new IgnoreListEntry(classname
, funcname
));
2006 m_ignore
.Add(new IgnoreListEntry(line
, ""));
2011 if ( *current
== '\0' )
2026 // -----------------------------------------------------------------------------
2027 // global function implementation
2028 // -----------------------------------------------------------------------------
2030 static wxString
MakeLabel(const char *classname
, const char *funcname
)
2032 wxString
label(classname
);
2033 if ( funcname
&& funcname
[0] == '\\' ) {
2034 // we may have some special TeX macro - so far only \destruct exists,
2035 // but may be later others will be added
2036 static const char *macros
[] = { "destruct" };
2037 static const char *replacement
[] = { "dtor" };
2040 for ( n
= 0; n
< WXSIZEOF(macros
); n
++ ) {
2041 if ( strncmp(funcname
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) {
2047 if ( n
== WXSIZEOF(macros
) ) {
2048 wxLogWarning("unknown function name '%s' - leaving as is.",
2052 funcname
= replacement
[n
];
2057 // special treatment for operatorXXX() stuff because the C operators
2058 // are not valid in LaTeX labels
2060 if ( wxString(funcname
).StartsWith("operator", &oper
) ) {
2061 label
<< "operator";
2074 for ( n
= 0; n
< WXSIZEOF(operatorNames
); n
++ ) {
2075 if ( oper
== operatorNames
[n
].oper
) {
2076 label
<< operatorNames
[n
].name
;
2082 if ( n
== WXSIZEOF(operatorNames
) ) {
2083 wxLogWarning("unknown operator '%s' - making dummy label.",
2089 else // simply use the func name
2100 static wxString
MakeHelpref(const char *argument
)
2103 helpref
<< "\\helpref{" << argument
<< "}{" << MakeLabel(argument
) << '}';
2108 static void TeXFilter(wxString
* str
)
2110 // TeX special which can be quoted (don't include backslash nor braces as
2112 static wxRegEx
reNonSpecialSpecials("[#$%&_]"),
2116 reNonSpecialSpecials
.ReplaceAll(str
, "\\\\\\0");
2118 // can't quote these ones as they produce accents when preceded by
2119 // backslash, so put them inside verb
2120 reAccents
.ReplaceAll(str
, "\\\\verb|\\0|");
2123 static void TeXUnfilter(wxString
* str
)
2125 // FIXME may be done much more quickly
2130 static wxRegEx
reNonSpecialSpecials("\\\\([#$%&_{}])"),
2131 reAccents("\\\\verb\\|([~^])\\|");
2133 reNonSpecialSpecials
.ReplaceAll(str
, "\\1");
2134 reAccents
.ReplaceAll(str
, "\\1");
2137 static wxString
GetAllComments(const spContext
& ctx
)
2140 const MCommentListT
& commentsList
= ctx
.GetCommentList();
2141 for ( MCommentListT::const_iterator i
= commentsList
.begin();
2142 i
!= commentsList
.end();
2144 wxString comment
= (*i
)->GetText();
2146 // don't take comments like "// ----------" &c
2147 comment
.Trim(FALSE
);
2149 comment
== wxString(comment
[0u], comment
.length() - 1) + '\n' )
2152 comments
<< comment
;
2158 static const char *GetCurrentTime(const char *timeFormat
)
2160 static char s_timeBuffer
[128];
2165 ptmNow
= localtime(&timeNow
);
2167 strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
);
2169 return s_timeBuffer
;
2172 static const wxString
GetVersionString()
2174 wxString version
= "$Revision$";
2175 wxRegEx("^\\$Revision$$").ReplaceFirst(&version
, "\\1");
2181 Revision 1.24 2003/08/13 22:59:37 VZ
2184 Revision 1.23 2003/06/13 17:05:43 VZ
2185 quote '|' inside regexes (fixes dump mode); fixed crash due to strange HelpGenApp code
2187 Revision 1.22 2002/01/21 21:18:50 JS
2188 Now adds 'include file' heading
2190 Revision 1.21 2002/01/04 11:06:09 JS
2191 Fixed missing membersections bug and also bug with functions not being written
2194 Revision 1.20 2002/01/03 14:23:33 JS
2195 Added code to make it not duplicate membersections for overloaded functions
2197 Revision 1.19 2002/01/03 13:34:12 JS
2198 Added FlushAll to CloseClass, otherwise text was only flushed right at the end,
2199 and appeared in one file.
2201 Revision 1.18 2002/01/03 12:02:47 JS
2202 Added main() and corrected VC++ project settings
2204 Revision 1.17 2001/11/30 21:43:35 VZ
2205 now the methods are sorted in the correct order in the generated docs
2207 Revision 1.16 2001/11/28 19:27:33 VZ
2208 HelpGen doesn't work in GUI mode
2210 Revision 1.15 2001/11/22 21:59:58 GD
2211 use "..." instead of <...> for wx headers
2213 Revision 1.14 2001/07/19 13:51:29 VZ
2214 fixes to version string
2216 Revision 1.13 2001/07/19 13:44:57 VZ
2217 1. compilation fixes
2218 2. don't quote special characters inside verbatim environment
2220 Revision 1.12 2000/10/09 13:53:33 juliansmart
2222 Doc corrections; added HelpGen project files
2224 Revision 1.11 2000/07/15 19:50:42 cvsuser
2227 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
2228 don't trasnform output dir name to lower case
2230 Revision 1.10 2000/03/11 10:05:23 VS
2231 now compiles with wxBase
2233 Revision 1.9 2000/01/16 13:25:21 VS
2234 compilation fixes (gcc)
2236 Revision 1.8 1999/09/13 14:29:39 JS
2238 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2239 into src for simplicity; added VC++ 5 project file
2241 Revision 1.7 1999/02/21 22:32:32 VZ
2242 1. more C++ parser fixes - now it almost parses wx/string.h
2243 a) #if/#ifdef/#else (very) limited support
2244 b) param type fix - now indirection chars are correctly handled
2245 c) class/struct/union distinction
2246 d) public/private fixes
2247 e) Dump() function added - very useful for debugging
2249 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2250 by default, and this option switches it on)
2252 Revision 1.6 1999/02/20 23:00:26 VZ
2253 1. new 'diff' mode which seems to work
2254 2. output files are not overwritten in 'dmup' mode
2255 3. fixes for better handling of const functions and operators
2256 ----------------------------
2258 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2259 1. Parser improvements
2260 a) const and virtual methods are parsed correctly (not static yet)
2261 b) "const" which is part of the return type is not swallowed
2263 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2264 "//---------" kind comments discarded now.
2265 ----------------------------
2267 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2269 some tweaks to HelpGen
2270 ----------------------------
2272 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2274 HelpGen starting to compile with VC++
2275 ----------------------------
2277 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2279 supports typedefs, generates "See also:" and adds "virtual " for virtual
2281 ----------------------------
2283 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2285 HelpGen is a prototype of the tool for automatic generation of the .tex files
2286 for wxWindows documentation from C++ headers
2289 /* vi: set tw=80 et ts=4 sw=4: */