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 #error "This is a console program and can be only compiled using wxBase"
59 #include "wx/string.h"
61 #include "wx/dynarray.h"
68 // C++ parsing classes
75 // argh, Windows defines this
80 // -----------------------------------------------------------------------------
82 // -----------------------------------------------------------------------------
84 class HelpGenApp
: public wxApp
89 // don't let wxWin parse our cmd line, we do it ourselves
90 virtual bool OnInit() { return TRUE
; }
95 // IMPLEMENT_APP(HelpGenApp);
97 // -----------------------------------------------------------------------------
99 // -----------------------------------------------------------------------------
101 // return the label for the given function name (i.e. argument of \label)
102 static wxString
MakeLabel(const char *classname
, const char *funcname
= NULL
);
104 // return the whole \helpref{arg}{arg_label} string
105 static wxString
MakeHelpref(const char *argument
);
107 // [un]quote special TeX characters (in place)
108 static void TeXFilter(wxString
* str
);
109 static void TeXUnfilter(wxString
* str
); // also trims spaces
111 // get all comments associated with this context
112 static wxString
GetAllComments(const spContext
& ctx
);
114 // get the string with current time (returns pointer to static buffer)
115 // timeFormat is used for the call of strftime(3)
116 static const char *GetCurrentTime(const char *timeFormat
);
118 // get the string containing the program version
119 static const wxString
GetVersionString();
121 // -----------------------------------------------------------------------------
123 // -----------------------------------------------------------------------------
125 // a function documentation entry
126 struct FunctionDocEntry
128 FunctionDocEntry(const wxString
& name_
, const wxString
& text_
)
129 : name(name_
), text(text_
) { }
134 // the function doc text
138 static int Compare(FunctionDocEntry
**pp1
, FunctionDocEntry
**pp2
)
140 // the methods should appear in the following order: ctors, dtor, all
141 // the rest in the alphabetical order
142 bool isCtor1
= (*pp1
)->name
== classname
;
143 bool isCtor2
= (*pp2
)->name
== classname
;
147 // we don't order the ctors because we don't know how to do it
151 // ctor comes before non-ctor
156 // non-ctor must come after ctor
160 wxString dtorname
= wxString('~') + classname
;
162 // there is only one dtor, so the logic here is simpler
163 if ( (*pp1
)->name
== dtorname
) {
166 else if ( (*pp2
)->name
== dtorname
) {
170 // two normal methods
171 return strcmp((*pp1
)->name
, (*pp2
)->name
);
175 static wxString classname
;
178 wxString
FunctionDocEntry::classname
;
180 WX_DECLARE_OBJARRAY(FunctionDocEntry
, FunctionDocEntries
);
182 #include "wx/arrimpl.cpp"
184 WX_DEFINE_OBJARRAY(FunctionDocEntries
);
186 // add a function which sanitazes the string before writing it to the file and
187 // also capable of delaying output and sorting it before really writing it to
188 // the file (done from FlushAll())
189 class wxTeXFile
: public wxFile
194 // write a string to file verbatim (should only be used for the strings
195 // inside verbatim environment)
196 void WriteVerbatim(const wxString
& s
)
201 // write a string quoting TeX specials in it
202 void WriteTeX(const wxString
& s
)
210 // do write everything to file
213 if ( m_text
.empty() )
216 if ( !Write(m_text
) ) {
217 wxLogError("Failed to output generated documentation.");
228 wxTeXFile(const wxTeXFile
&);
229 wxTeXFile
& operator=(const wxTeXFile
&);
234 // helper class which manages the classes and function names to ignore for
235 // the documentation purposes (used by both HelpGenVisitor and DocManager)
236 class IgnoreNamesHandler
239 IgnoreNamesHandler() : m_ignore(CompareIgnoreListEntries
) { }
240 ~IgnoreNamesHandler() { WX_CLEAR_ARRAY(m_ignore
); }
242 // load file with classes/functions to ignore (add them to the names we
244 bool AddNamesFromFile(const wxString
& filename
);
246 // return TRUE if we ignore this function
247 bool IgnoreMethod(const wxString
& classname
,
248 const wxString
& funcname
) const
250 if ( IgnoreClass(classname
) )
253 IgnoreListEntry
ignore(classname
, funcname
);
255 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
258 // return TRUE if we ignore this class entirely
259 bool IgnoreClass(const wxString
& classname
) const
261 IgnoreListEntry
ignore(classname
, "");
263 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
267 struct IgnoreListEntry
269 IgnoreListEntry(const wxString
& classname
,
270 const wxString
& funcname
)
271 : m_classname(classname
), m_funcname(funcname
)
275 wxString m_classname
;
276 wxString m_funcname
; // if empty, ignore class entirely
279 static int CompareIgnoreListEntries(IgnoreListEntry
*first
,
280 IgnoreListEntry
*second
);
282 // for efficiency, let's sort it
283 WX_DEFINE_SORTED_ARRAY(IgnoreListEntry
*, ArrayNamesToIgnore
);
285 ArrayNamesToIgnore m_ignore
;
288 IgnoreNamesHandler(const IgnoreNamesHandler
&);
289 IgnoreNamesHandler
& operator=(const IgnoreNamesHandler
&);
292 // visitor implementation which writes all collected data to a .tex file
293 class HelpGenVisitor
: public spVisitor
297 HelpGenVisitor(const wxString
& directoryOut
, bool overwrite
);
299 virtual void VisitFile( spFile
& fl
);
300 virtual void VisitClass( spClass
& cl
);
301 virtual void VisitEnumeration( spEnumeration
& en
);
302 virtual void VisitTypeDef( spTypeDef
& td
);
303 virtual void VisitPreprocessorLine( spPreprocessorLine
& pd
);
304 virtual void VisitAttribute( spAttribute
& attr
);
305 virtual void VisitOperation( spOperation
& op
);
306 virtual void VisitParameter( spParameter
& param
);
310 // get our `ignore' object
311 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
313 // shut up g++ warning (ain't it stupid?)
314 virtual ~HelpGenVisitor() { }
317 // (re)initialize the state
320 // insert documentation for enums/typedefs coming immediately before the
321 // class declaration into the class documentation
322 void InsertTypedefDocs();
323 void InsertEnumDocs();
325 // write the headers for corresponding sections (only once)
326 void InsertDataStructuresHeader();
327 void InsertMethodsHeader();
329 // terminate the function documentation if it was started
330 void CloseFunction();
332 // write out all function docs when there are no more left in this class
333 // after sorting them in alphabetical order
336 wxString m_directoryOut
, // directory for the output
337 m_fileHeader
; // name of the .h file we parse
338 bool m_overwrite
; // overwrite existing files?
339 wxTeXFile m_file
; // file we're writing to now
342 bool m_inClass
, // TRUE after file successfully opened
343 m_inTypesSection
, // enums & typedefs go there
344 m_inMethodSection
, // functions go here
345 m_isFirstParam
; // first parameter of current function?
347 // non empty while parsing a class
348 wxString m_classname
;
350 // these are only non-empty while parsing a method:
351 wxString m_funcName
, // the function name
352 m_textFunc
; // the function doc text
354 // the array containing the documentation entries for the functions in the
355 // class currently being parsed
356 FunctionDocEntries m_arrayFuncDocs
;
358 // holders for "saved" documentation
359 wxString m_textStoredTypedefs
,
360 m_textStoredFunctionComment
;
362 // for enums we have to use an array as we can't intermix the normal text
363 // and the text inside verbatim environment
364 wxArrayString m_storedEnums
,
367 // headers included by this file
368 wxArrayString m_headers
;
370 // ignore handler: tells us which classes to ignore for doc generation
372 IgnoreNamesHandler m_ignoreNames
;
375 HelpGenVisitor(const HelpGenVisitor
&);
376 HelpGenVisitor
& operator=(const HelpGenVisitor
&);
379 // documentation manager - a class which parses TeX files and remembers the
380 // functions documented in them and can later compare them with all functions
381 // found under ctxTop by C++ parser
385 DocManager(bool checkParamNames
);
388 // returns FALSE on failure
389 bool ParseTeXFile(const wxString
& filename
);
391 // returns FALSE if there were any differences
392 bool DumpDifferences(spContext
*ctxTop
) const;
394 // get our `ignore' object
395 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
401 // returns the length of 'match' if the string 'str' starts with it or 0
403 static size_t TryMatch(const char *str
, const char *match
);
405 // skip spaces: returns pointer to first non space character (also
406 // updates the value of m_line)
407 const char *SkipSpaces(const char *p
)
409 while ( isspace(*p
) ) {
417 // skips characters until the next 'c' in '*pp' unless it ends before in
418 // which case FALSE is returned and pp points to '\0', otherwise TRUE is
419 // returned and pp points to 'c'
420 bool SkipUntil(const char **pp
, char c
);
422 // the same as SkipUntil() but only spaces are skipped: on first non space
423 // character different from 'c' the function stops and returns FALSE
424 bool SkipSpaceUntil(const char **pp
, char c
);
426 // extract the string between {} and modify '*pp' to point at the
427 // character immediately after the closing '}'. The returned string is empty
429 wxString
ExtractStringBetweenBraces(const char **pp
);
431 // the current file and line while we're in ParseTeXFile (for error
436 // functions and classes to ignore during diff
437 // -------------------------------------------
439 IgnoreNamesHandler m_ignoreNames
;
441 // information about all functions documented in the TeX file(s)
442 // -------------------------------------------------------------
444 // info about a type: for now stored as text string, but must be parsed
445 // further later (to know that "char *" == "char []" - TODO)
449 TypeInfo(const wxString
& type
) : m_type(type
) { }
451 bool operator==(const wxString
& type
) const { return m_type
== type
; }
452 bool operator!=(const wxString
& type
) const { return m_type
!= type
; }
454 const wxString
& GetName() const { return m_type
; }
460 // info abotu a function parameter
464 ParamInfo(const wxString
& type
,
465 const wxString
& name
,
466 const wxString
& value
)
467 : m_type(type
), m_name(name
), m_value(value
)
471 const TypeInfo
& GetType() const { return m_type
; }
472 const wxString
& GetName() const { return m_name
; }
473 const wxString
& GetDefValue() const { return m_value
; }
476 TypeInfo m_type
; // type of parameter
477 wxString m_name
; // name
478 wxString m_value
; // default value
481 WX_DEFINE_ARRAY(ParamInfo
*, ArrayParamInfo
);
483 // info about a function
496 MethodInfo(const wxString
& type
,
497 const wxString
& name
,
498 const ArrayParamInfo
& params
)
499 : m_typeRet(type
), m_name(name
), m_params(params
)
504 void SetFlag(MethodFlags flag
) { m_flags
|= flag
; }
506 const TypeInfo
& GetType() const { return m_typeRet
; }
507 const wxString
& GetName() const { return m_name
; }
508 const ParamInfo
& GetParam(size_t n
) const { return *(m_params
[n
]); }
509 size_t GetParamCount() const { return m_params
.GetCount(); }
511 bool HasFlag(MethodFlags flag
) const { return (m_flags
& flag
) != 0; }
513 ~MethodInfo() { WX_CLEAR_ARRAY(m_params
); }
516 TypeInfo m_typeRet
; // return type
518 int m_flags
; // bit mask of the value from the enum above
520 ArrayParamInfo m_params
;
523 WX_DEFINE_ARRAY(MethodInfo
*, ArrayMethodInfo
);
524 WX_DEFINE_ARRAY(ArrayMethodInfo
*, ArrayMethodInfos
);
526 // first array contains the names of all classes we found, the second has a
527 // pointer to the array of methods of the given class at the same index as
528 // the class name appears in m_classes
529 wxArrayString m_classes
;
530 ArrayMethodInfos m_methods
;
532 // are we checking parameter names?
533 bool m_checkParamNames
;
536 DocManager(const DocManager
&);
537 DocManager
& operator=(const DocManager
&);
540 // =============================================================================
542 // =============================================================================
544 // this function never returns
547 wxString prog
= wxTheApp
->argv
[0];
548 wxString basename
= prog
.AfterLast('/');
551 basename
= prog
.AfterLast('\\');
557 "usage: %s [global options] <mode> [mode options] <files...>\n"
559 " where global options are:\n"
562 " -H give this usage message\n"
563 " -V print the version info\n"
564 " -i file file with classes/function to ignore\n"
566 " where mode is one of: dump, diff\n"
568 " dump means generate .tex files for TeX2RTF converter from specified\n"
569 " headers files, mode options are:\n"
570 " -f overwrite existing files\n"
571 " -o outdir directory for generated files\n"
573 " diff means compare the set of methods documented .tex file with the\n"
574 " methods declared in the header:\n"
575 " %s diff <file.h> <files.tex...>.\n"
576 " mode specific options are:\n"
577 " -p do check parameter names (not done by default)\n"
578 "\n", basename
.c_str(), basename
.c_str());
583 int HelpGenApp::OnRun()
596 wxArrayString filesH
, filesTeX
;
597 wxString directoryOut
, // directory for 'dmup' output
598 ignoreFile
; // file with classes/functions to ignore
599 bool overwrite
= FALSE
, // overwrite existing files during 'dump'?
600 paramNames
= FALSE
; // check param names during 'diff'?
602 for ( int current
= 1; current
< argc
; current
++ ) {
603 // all options have one letter
604 if ( argv
[current
][0] == '-' ) {
605 if ( argv
[current
][2] == '\0' ) {
606 switch ( argv
[current
][1] ) {
609 wxLog::GetActiveTarget()->SetVerbose();
614 wxLog::GetActiveTarget()->SetVerbose(FALSE
);
624 wxLogMessage("HelpGen version %s\n"
625 "(c) 1999-2001 Vadim Zeitlin\n",
626 GetVersionString().c_str());
631 if ( current
>= argc
) {
632 wxLogError("-i option requires an argument.");
637 ignoreFile
= argv
[current
];
641 if ( mode
!= Mode_Diff
) {
642 wxLogError("-p is only valid with diff.");
651 if ( mode
!= Mode_Dump
) {
652 wxLogError("-f is only valid with dump.");
661 if ( mode
!= Mode_Dump
) {
662 wxLogError("-o is only valid with dump.");
668 if ( current
>= argc
) {
669 wxLogError("-o option requires an argument.");
674 directoryOut
= argv
[current
];
675 if ( !!directoryOut
) {
676 // terminate with a '/' if it doesn't have it
677 switch ( directoryOut
.Last() ) {
688 //else: it's empty, do nothing
693 wxLogError("unknown option '%s'", argv
[current
]);
698 wxLogError("only one letter options are allowed, not '%s'.",
702 // only get here after a break from switch or from else branch of if
707 if ( mode
== Mode_None
) {
708 if ( strcmp(argv
[current
], "diff") == 0 )
710 else if ( strcmp(argv
[current
], "dump") == 0 )
713 wxLogError("unknown mode '%s'.", argv
[current
]);
719 if ( mode
== Mode_Dump
|| filesH
.IsEmpty() ) {
720 filesH
.Add(argv
[current
]);
723 // 2nd files and further are TeX files in diff mode
724 wxASSERT( mode
== Mode_Diff
);
726 filesTeX
.Add(argv
[current
]);
732 // create a parser object and a visitor derivation
733 CJSourceParser parser
;
734 HelpGenVisitor
visitor(directoryOut
, overwrite
);
735 if ( !!ignoreFile
&& mode
== Mode_Dump
)
736 visitor
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
738 spContext
*ctxTop
= NULL
;
740 // parse all header files
741 size_t nFiles
= filesH
.GetCount();
742 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
743 wxString header
= filesH
[n
];
744 ctxTop
= parser
.ParseFile(header
);
746 wxLogWarning("Header file '%s' couldn't be processed.",
749 else if ( mode
== Mode_Dump
) {
750 ((spFile
*)ctxTop
)->mFileName
= header
;
751 visitor
.VisitAll(*ctxTop
);
758 #endif // __WXDEBUG__
761 // parse all TeX files
762 if ( mode
== Mode_Diff
) {
764 wxLogError("Can't complete diff.");
770 DocManager
docman(paramNames
);
772 size_t nFiles
= filesTeX
.GetCount();
773 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
774 wxString file
= filesTeX
[n
];
775 if ( !docman
.ParseTeXFile(file
) ) {
776 wxLogWarning("TeX file '%s' couldn't be processed.",
782 docman
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
784 docman
.DumpDifferences(ctxTop
);
790 int main(int argc
, char **argv
)
792 wxInitializer initializer
;
795 fprintf(stderr
, "Failed to initialize the wxWindows library, aborting.");
805 // -----------------------------------------------------------------------------
806 // HelpGenVisitor implementation
807 // -----------------------------------------------------------------------------
809 HelpGenVisitor::HelpGenVisitor(const wxString
& directoryOut
,
811 : m_directoryOut(directoryOut
)
813 m_overwrite
= overwrite
;
818 void HelpGenVisitor::Reset()
822 m_inMethodSection
= FALSE
;
827 m_textStoredTypedefs
=
828 m_textStoredFunctionComment
= "";
830 m_arrayFuncDocs
.Empty();
832 m_storedEnums
.Empty();
833 m_storedEnumsVerb
.Empty();
837 void HelpGenVisitor::InsertTypedefDocs()
839 m_file
.WriteTeX(m_textStoredTypedefs
);
840 m_textStoredTypedefs
.Empty();
843 void HelpGenVisitor::InsertEnumDocs()
845 size_t count
= m_storedEnums
.GetCount();
846 for ( size_t n
= 0; n
< count
; n
++ )
848 m_file
.WriteTeX(m_storedEnums
[n
]);
849 m_file
.WriteVerbatim(m_storedEnumsVerb
[n
] + '\n');
852 m_storedEnums
.Empty();
853 m_storedEnumsVerb
.Empty();
856 void HelpGenVisitor::InsertDataStructuresHeader()
858 if ( !m_inTypesSection
) {
859 m_inTypesSection
= TRUE
;
861 m_file
.WriteVerbatim("\\wxheading{Data structures}\n\n");
865 void HelpGenVisitor::InsertMethodsHeader()
867 if ( !m_inMethodSection
) {
868 m_inMethodSection
= TRUE
;
870 m_file
.WriteVerbatim( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
874 void HelpGenVisitor::CloseFunction()
876 if ( !m_funcName
.empty() ) {
877 if ( m_isFirstParam
) {
879 m_textFunc
<< "\\void";
882 m_textFunc
<< "}\n\n";
884 if ( !m_textStoredFunctionComment
.IsEmpty() ) {
885 m_textFunc
<< m_textStoredFunctionComment
<< '\n';
888 m_arrayFuncDocs
.Add(new FunctionDocEntry(m_funcName
, m_textFunc
));
894 void HelpGenVisitor::CloseClass()
897 size_t count
= m_arrayFuncDocs
.GetCount();
899 FunctionDocEntry::classname
= m_classname
;
900 m_arrayFuncDocs
.Sort(FunctionDocEntry::Compare
);
902 for ( size_t n
= 0; n
< count
; n
++ ) {
903 m_file
.WriteTeX(m_arrayFuncDocs
[n
].text
);
906 m_arrayFuncDocs
.Empty();
915 void HelpGenVisitor::EndVisit()
921 m_fileHeader
.Empty();
924 if (m_file
.IsOpened())
930 wxLogVerbose("%s: finished generating for the current file.",
931 GetCurrentTime("%H:%M:%S"));
934 void HelpGenVisitor::VisitFile( spFile
& file
)
936 m_fileHeader
= file
.mFileName
;
937 wxLogVerbose("%s: started generating docs for classes from file '%s'...",
938 GetCurrentTime("%H:%M:%S"), m_fileHeader
.c_str());
941 void HelpGenVisitor::VisitClass( spClass
& cl
)
945 if (m_file
.IsOpened())
951 wxString name
= cl
.GetName();
953 if ( m_ignoreNames
.IgnoreClass(name
) ) {
954 wxLogVerbose("Skipping ignored class '%s'.", name
.c_str());
959 // the file name is built from the class name by removing the leading "wx"
960 // if any and converting it to the lower case
962 if ( name(0, 2) == "wx" ) {
963 filename
<< name
.c_str() + 2;
969 filename
.MakeLower();
971 filename
.Prepend(m_directoryOut
);
973 if ( !m_overwrite
&& wxFile::Exists(filename
) ) {
974 wxLogError("Won't overwrite existing file '%s' - please use '-f'.",
980 m_inClass
= m_file
.Open(filename
, wxFile::write
);
982 wxLogError("Can't generate documentation for the class '%s'.",
989 m_inTypesSection
= FALSE
;
991 wxLogInfo("Created new file '%s' for class '%s'.",
992 filename
.c_str(), name
.c_str());
994 // write out the header
997 "%% automatically generated by HelpGen %s from\n"
1002 "\\section{\\class{%s}}\\label{%s}\n\n",
1003 GetVersionString().c_str(),
1004 m_fileHeader
.c_str(),
1005 GetCurrentTime("%d/%b/%y %H:%M:%S"),
1007 wxString(name
).MakeLower().c_str());
1009 m_file
.WriteVerbatim(header
);
1011 // the entire text we're writing to file
1014 // if the header includes other headers they must be related to it... try to
1015 // automatically generate the "See also" clause
1016 if ( !m_headers
.IsEmpty() ) {
1017 // correspondence between wxWindows headers and class names
1018 static const char *headers
[] = {
1027 // NULL here means not to insert anything in "See also" for the
1028 // corresponding header
1029 static const char *classes
[] = {
1038 wxASSERT_MSG( WXSIZEOF(headers
) == WXSIZEOF(classes
),
1039 "arrays must be in sync!" );
1041 wxArrayInt interestingClasses
;
1043 size_t count
= m_headers
.Count(), index
;
1044 for ( size_t n
= 0; n
< count
; n
++ ) {
1045 wxString baseHeaderName
= m_headers
[n
].Before('.');
1046 if ( baseHeaderName(0, 3) != "wx/" )
1049 baseHeaderName
.erase(0, 3);
1050 for ( index
= 0; index
< WXSIZEOF(headers
); index
++ ) {
1051 if ( Stricmp(baseHeaderName
, headers
[index
]) == 0 )
1055 if ( (index
< WXSIZEOF(headers
)) && classes
[index
] ) {
1056 // interesting header
1057 interestingClasses
.Add(index
);
1061 if ( !interestingClasses
.IsEmpty() ) {
1062 // do generate "See also" clause
1063 totalText
<< "\\wxheading{See also:}\n\n";
1065 count
= interestingClasses
.Count();
1066 for ( index
= 0; index
< count
; index
++ ) {
1070 totalText
<< MakeHelpref(classes
[interestingClasses
[index
]]);
1073 totalText
<< "\n\n";
1077 // the comment before the class generally explains what is it for so put it
1078 // in place of the class description
1079 if ( cl
.HasComments() ) {
1080 wxString comment
= GetAllComments(cl
);
1082 totalText
<< '\n' << comment
<< '\n';
1085 // derived from section
1086 wxString derived
= "\\wxheading{Derived from}\n\n";
1088 const StrListT
& baseClasses
= cl
.mSuperClassNames
;
1089 if ( baseClasses
.size() == 0 ) {
1090 derived
<< "No base class";
1094 for ( StrListT::const_iterator i
= baseClasses
.begin();
1095 i
!= baseClasses
.end();
1098 // separate from the previous one
1099 derived
<< "\\\\\n";
1105 wxString baseclass
= *i
;
1106 derived
<< "\\helpref{" << baseclass
<< "}";
1107 derived
<< "{" << baseclass
.MakeLower() << "}";
1110 totalText
<< derived
<< "\n\n";
1112 // write all this to file
1113 m_file
.WriteTeX(totalText
);
1115 // if there were any enums/typedefs before, insert their documentation now
1116 InsertDataStructuresHeader();
1117 InsertTypedefDocs();
1123 void HelpGenVisitor::VisitEnumeration( spEnumeration
& en
)
1127 if ( m_inMethodSection
) {
1128 // FIXME that's a bug, but tell the user aboit it nevertheless... we
1129 // should be smart enough to process even the enums which come after the
1131 wxLogWarning("enum '%s' ignored, please put it before the class "
1132 "methods.", en
.GetName().c_str());
1136 // simply copy the enum text in the docs
1137 wxString enumeration
= GetAllComments(en
),
1140 enumerationVerb
<< "\\begin{verbatim}\n"
1142 << "\n\\end{verbatim}\n";
1144 // remember for later use if we're not inside a class yet
1146 m_storedEnums
.Add(enumeration
);
1147 m_storedEnumsVerb
.Add(enumerationVerb
);
1150 // write the header for this section if not done yet
1151 InsertDataStructuresHeader();
1153 m_file
.WriteTeX(enumeration
);
1154 m_file
.WriteVerbatim(enumerationVerb
);
1155 m_file
.WriteVerbatim('\n');
1159 void HelpGenVisitor::VisitTypeDef( spTypeDef
& td
)
1163 if ( m_inMethodSection
) {
1164 // FIXME that's a bug, but tell the user aboit it nevertheless...
1165 wxLogWarning("typedef '%s' ignored, please put it before the class "
1166 "methods.", td
.GetName().c_str());
1170 wxString typedefdoc
;
1171 typedefdoc
<< "{\\small \\begin{verbatim}\n"
1172 << "typedef " << td
.mOriginalType
<< ' ' << td
.GetName()
1173 << "\n\\end{verbatim}}\n"
1174 << GetAllComments(td
);
1176 // remember for later use if we're not inside a class yet
1178 if ( !m_textStoredTypedefs
.IsEmpty() ) {
1179 m_textStoredTypedefs
<< '\n';
1182 m_textStoredTypedefs
<< typedefdoc
;
1185 // write the header for this section if not done yet
1186 InsertDataStructuresHeader();
1189 m_file
.WriteTeX(typedefdoc
);
1193 void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine
& pd
)
1195 switch ( pd
.GetStatementType() ) {
1196 case SP_PREP_DEF_INCLUDE_FILE
:
1197 m_headers
.Add(pd
.CPP_GetIncludedFileNeme());
1200 case SP_PREP_DEF_DEFINE_SYMBOL
:
1201 // TODO decide if it's a constant and document it if it is
1206 void HelpGenVisitor::VisitAttribute( spAttribute
& attr
)
1210 // only document the public member variables
1211 if ( !m_inClass
|| !attr
.IsPublic() )
1214 wxLogWarning("Ignoring member variable '%s'.", attr
.GetName().c_str());
1217 void HelpGenVisitor::VisitOperation( spOperation
& op
)
1222 // we don't generate docs right now - either we ignore this class
1223 // entirely or we couldn't open the file
1227 if ( !op
.IsInClass() ) {
1228 // TODO document global functions
1229 wxLogWarning("skipped global function '%s'.", op
.GetName().c_str());
1234 if ( op
.mVisibility
== SP_VIS_PRIVATE
) {
1235 // FIXME should we document protected functions?
1239 m_classname
= op
.GetClass().GetName();
1240 wxString funcname
= op
.GetName();
1242 if ( m_ignoreNames
.IgnoreMethod(m_classname
, funcname
) ) {
1243 wxLogVerbose("Skipping ignored '%s::%s'.",
1244 m_classname
.c_str(), funcname
.c_str());
1249 InsertMethodsHeader();
1252 m_funcName
= funcname
;
1253 m_isFirstParam
= TRUE
;
1255 m_textStoredFunctionComment
= GetAllComments(op
);
1257 // start function documentation
1260 // check for the special case of dtor
1262 if ( (funcname
[0] == '~') && (m_classname
== funcname
.c_str() + 1) ) {
1263 dtor
.Printf("\\destruct{%s}", m_classname
.c_str());
1267 m_textFunc
.Printf("\n"
1268 "\\membersection{%s::%s}\\label{%s}\n"
1270 "\\%sfunc{%s%s}{%s}{",
1271 m_classname
.c_str(), funcname
.c_str(),
1272 MakeLabel(m_classname
, funcname
).c_str(),
1273 op
.mIsConstant
? "const" : "",
1274 op
.mIsVirtual
? "virtual " : "",
1275 op
.mRetType
.c_str(),
1279 void HelpGenVisitor::VisitParameter( spParameter
& param
)
1281 if ( m_funcName
.empty() )
1284 if ( m_isFirstParam
) {
1285 m_isFirstParam
= FALSE
;
1291 m_textFunc
<< "\\param{" << param
.mType
<< " }{" << param
.GetName();
1292 wxString defvalue
= param
.mInitVal
;
1293 if ( !defvalue
.IsEmpty() ) {
1294 m_textFunc
<< " = " << defvalue
;
1300 // ---------------------------------------------------------------------------
1302 // ---------------------------------------------------------------------------
1304 DocManager::DocManager(bool checkParamNames
)
1306 m_checkParamNames
= checkParamNames
;
1309 size_t DocManager::TryMatch(const char *str
, const char *match
)
1311 size_t lenMatch
= 0;
1312 while ( str
[lenMatch
] == match
[lenMatch
] ) {
1315 if ( match
[lenMatch
] == '\0' )
1322 bool DocManager::SkipUntil(const char **pp
, char c
)
1324 const char *p
= *pp
;
1340 bool DocManager::SkipSpaceUntil(const char **pp
, char c
)
1342 const char *p
= *pp
;
1344 if ( !isspace(*p
) || *p
== '\0' )
1358 wxString
DocManager::ExtractStringBetweenBraces(const char **pp
)
1362 if ( !SkipSpaceUntil(pp
, '{') ) {
1363 wxLogWarning("file %s(%d): '{' expected after '\\param'",
1364 m_filename
.c_str(), m_line
);
1368 const char *startParam
= ++*pp
; // skip '{'
1370 if ( !SkipUntil(pp
, '}') ) {
1371 wxLogWarning("file %s(%d): '}' expected after '\\param'",
1372 m_filename
.c_str(), m_line
);
1375 result
= wxString(startParam
, (*pp
)++ - startParam
);
1382 bool DocManager::ParseTeXFile(const wxString
& filename
)
1384 m_filename
= filename
;
1386 wxFile
file(m_filename
, wxFile::read
);
1387 if ( !file
.IsOpened() )
1390 off_t len
= file
.Length();
1391 if ( len
== wxInvalidOffset
)
1394 char *buf
= new char[len
+ 1];
1397 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1403 // reinit everything
1406 wxLogVerbose("%s: starting to parse doc file '%s'.",
1407 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1409 // the name of the class from the last "\membersection" command: we assume
1410 // that the following "\func" or "\constfunc" always documents a method of
1411 // this class (and it should always be like that in wxWindows documentation)
1414 for ( const char *current
= buf
; current
- buf
< len
; current
++ ) {
1415 // FIXME parsing is awfully inefficient
1417 if ( *current
== '%' ) {
1418 // comment, skip until the end of line
1420 SkipUntil(¤t
, '\n');
1425 // all the command we're interested in start with '\\'
1426 while ( *current
!= '\\' && *current
!= '\0' ) {
1427 if ( *current
++ == '\n' )
1431 if ( *current
== '\0' ) {
1432 // no more TeX commands left
1436 current
++; // skip '\\'
1444 } foundCommand
= Nothing
;
1446 size_t lenMatch
= TryMatch(current
, "func");
1448 foundCommand
= Func
;
1451 lenMatch
= TryMatch(current
, "constfunc");
1453 foundCommand
= ConstFunc
;
1455 lenMatch
= TryMatch(current
, "membersection");
1458 foundCommand
= MemberSect
;
1462 if ( foundCommand
== Nothing
)
1465 current
+= lenMatch
;
1467 if ( !SkipSpaceUntil(¤t
, '{') ) {
1468 wxLogWarning("file %s(%d): '{' expected after \\func, "
1469 "\\constfunc or \\membersection.",
1470 m_filename
.c_str(), m_line
);
1477 if ( foundCommand
== MemberSect
) {
1478 // what follows has the form <classname>::<funcname>
1479 const char *startClass
= current
;
1480 if ( !SkipUntil(¤t
, ':') || *(current
+ 1) != ':' ) {
1481 wxLogWarning("file %s(%d): '::' expected after "
1482 "\\membersection.", m_filename
.c_str(), m_line
);
1485 classname
= wxString(startClass
, current
- startClass
);
1486 TeXUnfilter(&classname
);
1492 // extract the return type
1493 const char *startRetType
= current
;
1495 if ( !SkipUntil(¤t
, '}') ) {
1496 wxLogWarning("file %s(%d): '}' expected after return type",
1497 m_filename
.c_str(), m_line
);
1502 wxString returnType
= wxString(startRetType
, current
- startRetType
);
1503 TeXUnfilter(&returnType
);
1506 if ( !SkipSpaceUntil(¤t
, '{') ) {
1507 wxLogWarning("file %s(%d): '{' expected after return type",
1508 m_filename
.c_str(), m_line
);
1514 const char *funcEnd
= current
;
1515 if ( !SkipUntil(&funcEnd
, '}') ) {
1516 wxLogWarning("file %s(%d): '}' expected after function name",
1517 m_filename
.c_str(), m_line
);
1522 wxString funcName
= wxString(current
, funcEnd
- current
);
1523 current
= funcEnd
+ 1;
1525 // trim spaces from both sides
1526 funcName
.Trim(FALSE
);
1527 funcName
.Trim(TRUE
);
1529 // special cases: '$...$' may be used for LaTeX inline math, remove the
1531 if ( funcName
.Find('$') != wxNOT_FOUND
) {
1533 for ( const char *p
= funcName
.c_str(); *p
!= '\0'; p
++ ) {
1534 if ( *p
!= '$' && !isspace(*p
) )
1541 // \destruct{foo} is really ~foo
1542 if ( funcName
[0u] == '\\' ) {
1543 size_t len
= strlen("\\destruct{");
1544 if ( funcName(0, len
) != "\\destruct{" ) {
1545 wxLogWarning("file %s(%d): \\destruct expected",
1546 m_filename
.c_str(), m_line
);
1551 funcName
.erase(0, len
);
1552 funcName
.Prepend('~');
1554 if ( !SkipSpaceUntil(¤t
, '}') ) {
1555 wxLogWarning("file %s(%d): '}' expected after destructor",
1556 m_filename
.c_str(), m_line
);
1561 funcEnd
++; // there is an extra '}' to count
1564 TeXUnfilter(&funcName
);
1567 current
= funcEnd
+ 1; // skip '}'
1568 if ( !SkipSpaceUntil(¤t
, '{') ||
1569 (current
++, !SkipSpaceUntil(¤t
, '\\')) ) {
1570 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1571 m_filename
.c_str(), m_line
);
1576 wxArrayString paramNames
, paramTypes
, paramValues
;
1578 bool isVararg
= FALSE
;
1580 current
++; // skip '\\'
1581 lenMatch
= TryMatch(current
, "void");
1583 lenMatch
= TryMatch(current
, "param");
1584 while ( lenMatch
&& (current
- buf
< len
) ) {
1585 current
+= lenMatch
;
1587 // now come {paramtype}{paramname}
1588 wxString paramType
= ExtractStringBetweenBraces(¤t
);
1589 if ( !!paramType
) {
1590 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1591 if ( !!paramText
) {
1592 // the param declaration may contain default value
1593 wxString paramName
= paramText
.BeforeFirst('='),
1594 paramValue
= paramText
.AfterFirst('=');
1596 // sanitize all strings
1597 TeXUnfilter(¶mValue
);
1598 TeXUnfilter(¶mName
);
1599 TeXUnfilter(¶mType
);
1601 paramValues
.Add(paramValue
);
1602 paramNames
.Add(paramName
);
1603 paramTypes
.Add(paramType
);
1608 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1609 if ( paramText
== "..." ) {
1613 wxLogWarning("Parameters of '%s::%s' are in "
1615 classname
.c_str(), funcName
.c_str());
1620 current
= SkipSpaces(current
);
1621 if ( *current
== ',' || *current
== '}' ) {
1622 current
= SkipSpaces(++current
);
1624 lenMatch
= TryMatch(current
, "\\param");
1627 wxLogWarning("file %s(%d): ',' or '}' expected after "
1628 "'\\param'", m_filename
.c_str(), m_line
);
1634 // if we got here there was no '\\void', so must have some params
1635 if ( paramNames
.IsEmpty() ) {
1636 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1637 m_filename
.c_str(), m_line
);
1643 // verbose diagnostic output
1645 size_t param
, paramCount
= paramNames
.GetCount();
1646 for ( param
= 0; param
< paramCount
; param
++ ) {
1651 paramsAll
<< paramTypes
[param
] << ' ' << paramNames
[param
];
1654 wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
1655 m_filename
.c_str(), m_line
,
1660 foundCommand
== ConstFunc
? " const" : "");
1662 // store the info about the just found function
1663 ArrayMethodInfo
*methods
;
1664 int index
= m_classes
.Index(classname
);
1665 if ( index
== wxNOT_FOUND
) {
1666 m_classes
.Add(classname
);
1668 methods
= new ArrayMethodInfo
;
1669 m_methods
.Add(methods
);
1672 methods
= m_methods
[(size_t)index
];
1675 ArrayParamInfo params
;
1676 for ( param
= 0; param
< paramCount
; param
++ ) {
1677 params
.Add(new ParamInfo(paramTypes
[param
],
1679 paramValues
[param
]));
1682 MethodInfo
*method
= new MethodInfo(returnType
, funcName
, params
);
1683 if ( foundCommand
== ConstFunc
)
1684 method
->SetFlag(MethodInfo::Const
);
1686 method
->SetFlag(MethodInfo::Vararg
);
1688 methods
->Add(method
);
1693 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1694 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1699 bool DocManager::DumpDifferences(spContext
*ctxTop
) const
1701 typedef MMemberListT::const_iterator MemberIndex
;
1703 bool foundDiff
= FALSE
;
1705 // flag telling us whether the given class was found at all in the header
1706 size_t nClass
, countClassesInDocs
= m_classes
.GetCount();
1707 bool *classExists
= new bool[countClassesInDocs
];
1708 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1709 classExists
[nClass
] = FALSE
;
1712 // ctxTop is normally an spFile
1713 wxASSERT( ctxTop
->GetContextType() == SP_CTX_FILE
);
1715 const MMemberListT
& classes
= ctxTop
->GetMembers();
1716 for ( MemberIndex i
= classes
.begin(); i
!= classes
.end(); i
++ ) {
1717 spContext
*ctx
= *i
;
1718 if ( ctx
->GetContextType() != SP_CTX_CLASS
) {
1719 // TODO process also global functions, macros, ...
1723 spClass
*ctxClass
= (spClass
*)ctx
;
1724 const wxString
& nameClass
= ctxClass
->mName
;
1725 int index
= m_classes
.Index(nameClass
);
1726 if ( index
== wxNOT_FOUND
) {
1727 if ( !m_ignoreNames
.IgnoreClass(nameClass
) ) {
1730 wxLogError("Class '%s' is not documented at all.",
1734 // it makes no sense to check for its functions
1738 classExists
[index
] = TRUE
;
1741 // array of method descriptions for this class
1742 const ArrayMethodInfo
& methods
= *(m_methods
[index
]);
1743 size_t nMethod
, countMethods
= methods
.GetCount();
1745 // flags telling if we already processed given function
1746 bool *methodExists
= new bool[countMethods
];
1747 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1748 methodExists
[nMethod
] = FALSE
;
1751 wxArrayString aOverloadedMethods
;
1753 const MMemberListT
& functions
= ctxClass
->GetMembers();
1754 for ( MemberIndex j
= functions
.begin(); j
!= functions
.end(); j
++ ) {
1756 if ( ctx
->GetContextType() != SP_CTX_OPERATION
)
1759 spOperation
*ctxMethod
= (spOperation
*)ctx
;
1760 const wxString
& nameMethod
= ctxMethod
->mName
;
1762 // find all functions with the same name
1763 wxArrayInt aMethodsWithSameName
;
1764 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1765 if ( methods
[nMethod
]->GetName() == nameMethod
)
1766 aMethodsWithSameName
.Add(nMethod
);
1769 if ( aMethodsWithSameName
.IsEmpty() && ctxMethod
->IsPublic() ) {
1770 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1773 wxLogError("'%s::%s' is not documented.",
1775 nameMethod
.c_str());
1778 // don't check params
1781 else if ( aMethodsWithSameName
.GetCount() == 1 ) {
1782 index
= (size_t)aMethodsWithSameName
[0u];
1783 methodExists
[index
] = TRUE
;
1785 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1788 if ( !ctxMethod
->IsPublic() ) {
1789 wxLogWarning("'%s::%s' is documented but not public.",
1791 nameMethod
.c_str());
1794 // check that the flags match
1795 const MethodInfo
& method
= *(methods
[index
]);
1797 bool isVirtual
= ctxMethod
->mIsVirtual
;
1798 if ( isVirtual
!= method
.HasFlag(MethodInfo::Virtual
) ) {
1799 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1803 isVirtual
? "not " : "");
1806 bool isConst
= ctxMethod
->mIsConstant
;
1807 if ( isConst
!= method
.HasFlag(MethodInfo::Const
) ) {
1808 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1812 isConst
? "not " : "");
1815 // check that the params match
1816 const MMemberListT
& params
= ctxMethod
->GetMembers();
1818 if ( params
.size() != method
.GetParamCount() ) {
1819 wxLogError("Incorrect number of parameters for '%s::%s' "
1820 "in the docs: should be %d instead of %d.",
1823 params
.size(), method
.GetParamCount());
1827 for ( MemberIndex k
= params
.begin();
1832 // what else can a function have?
1833 wxASSERT( ctx
->GetContextType() == SP_CTX_PARAMETER
);
1835 spParameter
*ctxParam
= (spParameter
*)ctx
;
1836 const ParamInfo
& param
= method
.GetParam(nParam
);
1837 if ( m_checkParamNames
&&
1838 (param
.GetName() != ctxParam
->mName
) ) {
1841 wxLogError("Parameter #%d of '%s::%s' should be "
1842 "'%s' and not '%s'.",
1846 ctxParam
->mName
.c_str(),
1847 param
.GetName().c_str());
1852 if ( param
.GetType() != ctxParam
->mType
) {
1855 wxLogError("Type of parameter '%s' of '%s::%s' "
1856 "should be '%s' and not '%s'.",
1857 ctxParam
->mName
.c_str(),
1860 ctxParam
->mType
.c_str(),
1861 param
.GetType().GetName().c_str());
1866 if ( param
.GetDefValue() != ctxParam
->mInitVal
) {
1867 wxLogWarning("Default value of parameter '%s' of "
1868 "'%s::%s' should be '%s' and not "
1870 ctxParam
->mName
.c_str(),
1873 ctxParam
->mInitVal
.c_str(),
1874 param
.GetDefValue().c_str());
1880 // TODO OVER add real support for overloaded methods
1882 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1885 if ( aOverloadedMethods
.Index(nameMethod
) == wxNOT_FOUND
) {
1886 // mark all methods with this name as existing
1887 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1888 if ( methods
[nMethod
]->GetName() == nameMethod
)
1889 methodExists
[nMethod
] = TRUE
;
1892 aOverloadedMethods
.Add(nameMethod
);
1894 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1895 "stupid to find the right match - skipping "
1896 "the param and flags checks.",
1898 nameMethod
.c_str());
1900 //else: warning already given
1904 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1905 if ( !methodExists
[nMethod
] ) {
1906 const wxString
& nameMethod
= methods
[nMethod
]->GetName();
1907 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1910 wxLogError("'%s::%s' is documented but doesn't exist.",
1912 nameMethod
.c_str());
1917 delete [] methodExists
;
1920 // check that all classes we found in the docs really exist
1921 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1922 if ( !classExists
[nClass
] ) {
1925 wxLogError("Class '%s' is documented but doesn't exist.",
1926 m_classes
[nClass
].c_str());
1930 delete [] classExists
;
1935 DocManager::~DocManager()
1937 WX_CLEAR_ARRAY(m_methods
);
1940 // ---------------------------------------------------------------------------
1941 // IgnoreNamesHandler implementation
1942 // ---------------------------------------------------------------------------
1944 int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry
*first
,
1945 IgnoreListEntry
*second
)
1947 // first compare the classes
1948 int rc
= first
->m_classname
.Cmp(second
->m_classname
);
1950 rc
= first
->m_funcname
.Cmp(second
->m_funcname
);
1955 bool IgnoreNamesHandler::AddNamesFromFile(const wxString
& filename
)
1957 wxFile
file(filename
, wxFile::read
);
1958 if ( !file
.IsOpened() )
1961 off_t len
= file
.Length();
1962 if ( len
== wxInvalidOffset
)
1965 char *buf
= new char[len
+ 1];
1968 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1975 for ( const char *current
= buf
; ; current
++ ) {
1977 // skip DOS line separator
1978 if ( *current
== '\r' )
1982 if ( *current
== '\n' || *current
== '\0' ) {
1983 if ( line
[0u] != '#' ) {
1984 if ( line
.Find(':') != wxNOT_FOUND
) {
1985 wxString classname
= line
.BeforeFirst(':'),
1986 funcname
= line
.AfterLast(':');
1987 m_ignore
.Add(new IgnoreListEntry(classname
, funcname
));
1991 m_ignore
.Add(new IgnoreListEntry(line
, ""));
1996 if ( *current
== '\0' )
2011 // -----------------------------------------------------------------------------
2012 // global function implementation
2013 // -----------------------------------------------------------------------------
2015 static wxString
MakeLabel(const char *classname
, const char *funcname
)
2017 wxString
label(classname
);
2018 if ( funcname
&& funcname
[0] == '\\' ) {
2019 // we may have some special TeX macro - so far only \destruct exists,
2020 // but may be later others will be added
2021 static const char *macros
[] = { "destruct" };
2022 static const char *replacement
[] = { "dtor" };
2025 for ( n
= 0; n
< WXSIZEOF(macros
); n
++ ) {
2026 if ( strncmp(funcname
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) {
2032 if ( n
== WXSIZEOF(macros
) ) {
2033 wxLogWarning("unknown function name '%s' - leaving as is.",
2037 funcname
= replacement
[n
];
2042 // special treatment for operatorXXX() stuff because the C operators
2043 // are not valid in LaTeX labels
2045 if ( wxString(funcname
).StartsWith("operator", &oper
) ) {
2046 label
<< "operator";
2059 for ( n
= 0; n
< WXSIZEOF(operatorNames
); n
++ ) {
2060 if ( oper
== operatorNames
[n
].oper
) {
2061 label
<< operatorNames
[n
].name
;
2067 if ( n
== WXSIZEOF(operatorNames
) ) {
2068 wxLogWarning("unknown operator '%s' - making dummy label.",
2074 else // simply use the func name
2085 static wxString
MakeHelpref(const char *argument
)
2088 helpref
<< "\\helpref{" << argument
<< "}{" << MakeLabel(argument
) << '}';
2093 static void TeXFilter(wxString
* str
)
2095 // TeX special which can be quoted (don't include backslash nor braces as
2097 static wxRegEx
reNonSpecialSpecials("[#$%&_]"),
2101 reNonSpecialSpecials
.ReplaceAll(str
, "\\\\\\0");
2103 // can't quote these ones as they produce accents when preceded by
2104 // backslash, so put them inside verb
2105 reAccents
.ReplaceAll(str
, "\\\\verb|\\0|");
2108 static void TeXUnfilter(wxString
* str
)
2110 // FIXME may be done much more quickly
2115 static wxRegEx
reNonSpecialSpecials("\\\\([#$%&_{}])"),
2116 reAccents("\\\\verb|([~^])|");
2118 reNonSpecialSpecials
.ReplaceAll(str
, "\\1");
2119 reAccents
.ReplaceAll(str
, "\\1");
2122 static wxString
GetAllComments(const spContext
& ctx
)
2125 const MCommentListT
& commentsList
= ctx
.GetCommentList();
2126 for ( MCommentListT::const_iterator i
= commentsList
.begin();
2127 i
!= commentsList
.end();
2129 wxString comment
= (*i
)->GetText();
2131 // don't take comments like "// ----------" &c
2132 comment
.Trim(FALSE
);
2134 comment
== wxString(comment
[0u], comment
.length() - 1) + '\n' )
2137 comments
<< comment
;
2143 static const char *GetCurrentTime(const char *timeFormat
)
2145 static char s_timeBuffer
[128];
2150 ptmNow
= localtime(&timeNow
);
2152 strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
);
2154 return s_timeBuffer
;
2157 static const wxString
GetVersionString()
2159 wxString version
= "$Revision$";
2160 wxRegEx("^\\$Revision$$").ReplaceFirst(&version
, "\\1");
2166 Revision 1.19 2002/01/03 13:34:12 JS
2167 Added FlushAll to CloseClass, otherwise text was only flushed right at the end,
2168 and appeared in one file.
2170 Revision 1.18 2002/01/03 12:02:47 JS
2171 Added main() and corrected VC++ project settings
2173 Revision 1.17 2001/11/30 21:43:35 VZ
2174 now the methods are sorted in the correct order in the generated docs
2176 Revision 1.16 2001/11/28 19:27:33 VZ
2177 HelpGen doesn't work in GUI mode
2179 Revision 1.15 2001/11/22 21:59:58 GD
2180 use "..." instead of <...> for wx headers
2182 Revision 1.14 2001/07/19 13:51:29 VZ
2183 fixes to version string
2185 Revision 1.13 2001/07/19 13:44:57 VZ
2186 1. compilation fixes
2187 2. don't quote special characters inside verbatim environment
2189 Revision 1.12 2000/10/09 13:53:33 juliansmart
2191 Doc corrections; added HelpGen project files
2193 Revision 1.11 2000/07/15 19:50:42 cvsuser
2196 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
2197 don't trasnform output dir name to lower case
2199 Revision 1.10 2000/03/11 10:05:23 VS
2200 now compiles with wxBase
2202 Revision 1.9 2000/01/16 13:25:21 VS
2203 compilation fixes (gcc)
2205 Revision 1.8 1999/09/13 14:29:39 JS
2207 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2208 into src for simplicity; added VC++ 5 project file
2210 Revision 1.7 1999/02/21 22:32:32 VZ
2211 1. more C++ parser fixes - now it almost parses wx/string.h
2212 a) #if/#ifdef/#else (very) limited support
2213 b) param type fix - now indirection chars are correctly handled
2214 c) class/struct/union distinction
2215 d) public/private fixes
2216 e) Dump() function added - very useful for debugging
2218 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2219 by default, and this option switches it on)
2221 Revision 1.6 1999/02/20 23:00:26 VZ
2222 1. new 'diff' mode which seems to work
2223 2. output files are not overwritten in 'dmup' mode
2224 3. fixes for better handling of const functions and operators
2225 ----------------------------
2227 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2228 1. Parser improvements
2229 a) const and virtual methods are parsed correctly (not static yet)
2230 b) "const" which is part of the return type is not swallowed
2232 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2233 "//---------" kind comments discarded now.
2234 ----------------------------
2236 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2238 some tweaks to HelpGen
2239 ----------------------------
2241 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2243 HelpGen starting to compile with VC++
2244 ----------------------------
2246 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2248 supports typedefs, generates "See also:" and adds "virtual " for virtual
2250 ----------------------------
2252 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2254 HelpGen is a prototype of the tool for automatic generation of the .tex files
2255 for wxWindows documentation from C++ headers
2258 /* vi: set tw=80 et ts=4 sw=4: */