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 // -----------------------------------------------------------------------------
791 // HelpGenVisitor implementation
792 // -----------------------------------------------------------------------------
794 HelpGenVisitor::HelpGenVisitor(const wxString
& directoryOut
,
796 : m_directoryOut(directoryOut
)
798 m_overwrite
= overwrite
;
803 void HelpGenVisitor::Reset()
807 m_inMethodSection
= FALSE
;
812 m_textStoredTypedefs
=
813 m_textStoredFunctionComment
= "";
815 m_arrayFuncDocs
.Empty();
817 m_storedEnums
.Empty();
818 m_storedEnumsVerb
.Empty();
822 void HelpGenVisitor::InsertTypedefDocs()
824 m_file
.WriteTeX(m_textStoredTypedefs
);
825 m_textStoredTypedefs
.Empty();
828 void HelpGenVisitor::InsertEnumDocs()
830 size_t count
= m_storedEnums
.GetCount();
831 for ( size_t n
= 0; n
< count
; n
++ )
833 m_file
.WriteTeX(m_storedEnums
[n
]);
834 m_file
.WriteVerbatim(m_storedEnumsVerb
[n
] + '\n');
837 m_storedEnums
.Empty();
838 m_storedEnumsVerb
.Empty();
841 void HelpGenVisitor::InsertDataStructuresHeader()
843 if ( !m_inTypesSection
) {
844 m_inTypesSection
= TRUE
;
846 m_file
.WriteVerbatim("\\wxheading{Data structures}\n\n");
850 void HelpGenVisitor::InsertMethodsHeader()
852 if ( !m_inMethodSection
) {
853 m_inMethodSection
= TRUE
;
855 m_file
.WriteVerbatim( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
859 void HelpGenVisitor::CloseFunction()
861 if ( !m_funcName
.empty() ) {
862 if ( m_isFirstParam
) {
864 m_textFunc
<< "\\void";
867 m_textFunc
<< "}\n\n";
869 if ( !m_textStoredFunctionComment
.IsEmpty() ) {
870 m_textFunc
<< m_textStoredFunctionComment
<< '\n';
873 m_arrayFuncDocs
.Add(new FunctionDocEntry(m_funcName
, m_textFunc
));
879 void HelpGenVisitor::CloseClass()
882 size_t count
= m_arrayFuncDocs
.GetCount();
884 FunctionDocEntry::classname
= m_classname
;
885 m_arrayFuncDocs
.Sort(FunctionDocEntry::Compare
);
887 for ( size_t n
= 0; n
< count
; n
++ ) {
888 m_file
.WriteTeX(m_arrayFuncDocs
[n
].text
);
891 m_arrayFuncDocs
.Empty();
899 void HelpGenVisitor::EndVisit()
905 m_fileHeader
.Empty();
909 wxLogVerbose("%s: finished generating for the current file.",
910 GetCurrentTime("%H:%M:%S"));
913 void HelpGenVisitor::VisitFile( spFile
& file
)
915 m_fileHeader
= file
.mFileName
;
916 wxLogVerbose("%s: started generating docs for classes from file '%s'...",
917 GetCurrentTime("%H:%M:%S"), m_fileHeader
.c_str());
920 void HelpGenVisitor::VisitClass( spClass
& cl
)
924 wxString name
= cl
.GetName();
926 if ( m_ignoreNames
.IgnoreClass(name
) ) {
927 wxLogVerbose("Skipping ignored class '%s'.", name
.c_str());
932 // the file name is built from the class name by removing the leading "wx"
933 // if any and converting it to the lower case
935 if ( name(0, 2) == "wx" ) {
936 filename
<< name
.c_str() + 2;
942 filename
.MakeLower();
944 filename
.Prepend(m_directoryOut
);
946 if ( !m_overwrite
&& wxFile::Exists(filename
) ) {
947 wxLogError("Won't overwrite existing file '%s' - please use '-f'.",
953 m_inClass
= m_file
.Open(filename
, wxFile::write
);
955 wxLogError("Can't generate documentation for the class '%s'.",
962 m_inTypesSection
= FALSE
;
964 wxLogInfo("Created new file '%s' for class '%s'.",
965 filename
.c_str(), name
.c_str());
967 // write out the header
970 "%% automatically generated by HelpGen %s from\n"
975 "\\section{\\class{%s}}\\label{%s}\n\n",
976 GetVersionString().c_str(),
977 m_fileHeader
.c_str(),
978 GetCurrentTime("%d/%b/%y %H:%M:%S"),
980 wxString(name
).MakeLower().c_str());
982 m_file
.WriteVerbatim(header
);
984 // the entire text we're writing to file
987 // if the header includes other headers they must be related to it... try to
988 // automatically generate the "See also" clause
989 if ( !m_headers
.IsEmpty() ) {
990 // correspondence between wxWindows headers and class names
991 static const char *headers
[] = {
1000 // NULL here means not to insert anything in "See also" for the
1001 // corresponding header
1002 static const char *classes
[] = {
1011 wxASSERT_MSG( WXSIZEOF(headers
) == WXSIZEOF(classes
),
1012 "arrays must be in sync!" );
1014 wxArrayInt interestingClasses
;
1016 size_t count
= m_headers
.Count(), index
;
1017 for ( size_t n
= 0; n
< count
; n
++ ) {
1018 wxString baseHeaderName
= m_headers
[n
].Before('.');
1019 if ( baseHeaderName(0, 3) != "wx/" )
1022 baseHeaderName
.erase(0, 3);
1023 for ( index
= 0; index
< WXSIZEOF(headers
); index
++ ) {
1024 if ( Stricmp(baseHeaderName
, headers
[index
]) == 0 )
1028 if ( (index
< WXSIZEOF(headers
)) && classes
[index
] ) {
1029 // interesting header
1030 interestingClasses
.Add(index
);
1034 if ( !interestingClasses
.IsEmpty() ) {
1035 // do generate "See also" clause
1036 totalText
<< "\\wxheading{See also:}\n\n";
1038 count
= interestingClasses
.Count();
1039 for ( index
= 0; index
< count
; index
++ ) {
1043 totalText
<< MakeHelpref(classes
[interestingClasses
[index
]]);
1046 totalText
<< "\n\n";
1050 // the comment before the class generally explains what is it for so put it
1051 // in place of the class description
1052 if ( cl
.HasComments() ) {
1053 wxString comment
= GetAllComments(cl
);
1055 totalText
<< '\n' << comment
<< '\n';
1058 // derived from section
1059 wxString derived
= "\\wxheading{Derived from}\n\n";
1061 const StrListT
& baseClasses
= cl
.mSuperClassNames
;
1062 if ( baseClasses
.size() == 0 ) {
1063 derived
<< "No base class";
1067 for ( StrListT::const_iterator i
= baseClasses
.begin();
1068 i
!= baseClasses
.end();
1071 // separate from the previous one
1072 derived
<< "\\\\\n";
1078 wxString baseclass
= *i
;
1079 derived
<< "\\helpref{" << baseclass
<< "}";
1080 derived
<< "{" << baseclass
.MakeLower() << "}";
1083 totalText
<< derived
<< "\n\n";
1085 // write all this to file
1086 m_file
.WriteTeX(totalText
);
1088 // if there were any enums/typedefs before, insert their documentation now
1089 InsertDataStructuresHeader();
1090 InsertTypedefDocs();
1094 void HelpGenVisitor::VisitEnumeration( spEnumeration
& en
)
1098 if ( m_inMethodSection
) {
1099 // FIXME that's a bug, but tell the user aboit it nevertheless... we
1100 // should be smart enough to process even the enums which come after the
1102 wxLogWarning("enum '%s' ignored, please put it before the class "
1103 "methods.", en
.GetName().c_str());
1107 // simply copy the enum text in the docs
1108 wxString enumeration
= GetAllComments(en
),
1111 enumerationVerb
<< "\\begin{verbatim}\n"
1113 << "\n\\end{verbatim}\n";
1115 // remember for later use if we're not inside a class yet
1117 m_storedEnums
.Add(enumeration
);
1118 m_storedEnumsVerb
.Add(enumerationVerb
);
1121 // write the header for this section if not done yet
1122 InsertDataStructuresHeader();
1124 m_file
.WriteTeX(enumeration
);
1125 m_file
.WriteVerbatim(enumerationVerb
);
1126 m_file
.WriteVerbatim('\n');
1130 void HelpGenVisitor::VisitTypeDef( spTypeDef
& td
)
1134 if ( m_inMethodSection
) {
1135 // FIXME that's a bug, but tell the user aboit it nevertheless...
1136 wxLogWarning("typedef '%s' ignored, please put it before the class "
1137 "methods.", td
.GetName().c_str());
1141 wxString typedefdoc
;
1142 typedefdoc
<< "{\\small \\begin{verbatim}\n"
1143 << "typedef " << td
.mOriginalType
<< ' ' << td
.GetName()
1144 << "\n\\end{verbatim}}\n"
1145 << GetAllComments(td
);
1147 // remember for later use if we're not inside a class yet
1149 if ( !m_textStoredTypedefs
.IsEmpty() ) {
1150 m_textStoredTypedefs
<< '\n';
1153 m_textStoredTypedefs
<< typedefdoc
;
1156 // write the header for this section if not done yet
1157 InsertDataStructuresHeader();
1160 m_file
.WriteTeX(typedefdoc
);
1164 void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine
& pd
)
1166 switch ( pd
.GetStatementType() ) {
1167 case SP_PREP_DEF_INCLUDE_FILE
:
1168 m_headers
.Add(pd
.CPP_GetIncludedFileNeme());
1171 case SP_PREP_DEF_DEFINE_SYMBOL
:
1172 // TODO decide if it's a constant and document it if it is
1177 void HelpGenVisitor::VisitAttribute( spAttribute
& attr
)
1181 // only document the public member variables
1182 if ( !m_inClass
|| !attr
.IsPublic() )
1185 wxLogWarning("Ignoring member variable '%s'.", attr
.GetName().c_str());
1188 void HelpGenVisitor::VisitOperation( spOperation
& op
)
1193 // we don't generate docs right now - either we ignore this class
1194 // entirely or we couldn't open the file
1198 if ( !op
.IsInClass() ) {
1199 // TODO document global functions
1200 wxLogWarning("skipped global function '%s'.", op
.GetName().c_str());
1205 if ( op
.mVisibility
== SP_VIS_PRIVATE
) {
1206 // FIXME should we document protected functions?
1210 m_classname
= op
.GetClass().GetName();
1211 wxString funcname
= op
.GetName();
1213 if ( m_ignoreNames
.IgnoreMethod(m_classname
, funcname
) ) {
1214 wxLogVerbose("Skipping ignored '%s::%s'.",
1215 m_classname
.c_str(), funcname
.c_str());
1220 InsertMethodsHeader();
1223 m_funcName
= funcname
;
1224 m_isFirstParam
= TRUE
;
1226 m_textStoredFunctionComment
= GetAllComments(op
);
1228 // start function documentation
1231 // check for the special case of dtor
1233 if ( (funcname
[0] == '~') && (m_classname
== funcname
.c_str() + 1) ) {
1234 dtor
.Printf("\\destruct{%s}", m_classname
.c_str());
1238 m_textFunc
.Printf("\n"
1239 "\\membersection{%s::%s}\\label{%s}\n"
1241 "\\%sfunc{%s%s}{%s}{",
1242 m_classname
.c_str(), funcname
.c_str(),
1243 MakeLabel(m_classname
, funcname
).c_str(),
1244 op
.mIsConstant
? "const" : "",
1245 op
.mIsVirtual
? "virtual " : "",
1246 op
.mRetType
.c_str(),
1250 void HelpGenVisitor::VisitParameter( spParameter
& param
)
1252 if ( m_funcName
.empty() )
1255 if ( m_isFirstParam
) {
1256 m_isFirstParam
= FALSE
;
1262 m_textFunc
<< "\\param{" << param
.mType
<< " }{" << param
.GetName();
1263 wxString defvalue
= param
.mInitVal
;
1264 if ( !defvalue
.IsEmpty() ) {
1265 m_textFunc
<< " = " << defvalue
;
1271 // ---------------------------------------------------------------------------
1273 // ---------------------------------------------------------------------------
1275 DocManager::DocManager(bool checkParamNames
)
1277 m_checkParamNames
= checkParamNames
;
1280 size_t DocManager::TryMatch(const char *str
, const char *match
)
1282 size_t lenMatch
= 0;
1283 while ( str
[lenMatch
] == match
[lenMatch
] ) {
1286 if ( match
[lenMatch
] == '\0' )
1293 bool DocManager::SkipUntil(const char **pp
, char c
)
1295 const char *p
= *pp
;
1311 bool DocManager::SkipSpaceUntil(const char **pp
, char c
)
1313 const char *p
= *pp
;
1315 if ( !isspace(*p
) || *p
== '\0' )
1329 wxString
DocManager::ExtractStringBetweenBraces(const char **pp
)
1333 if ( !SkipSpaceUntil(pp
, '{') ) {
1334 wxLogWarning("file %s(%d): '{' expected after '\\param'",
1335 m_filename
.c_str(), m_line
);
1339 const char *startParam
= ++*pp
; // skip '{'
1341 if ( !SkipUntil(pp
, '}') ) {
1342 wxLogWarning("file %s(%d): '}' expected after '\\param'",
1343 m_filename
.c_str(), m_line
);
1346 result
= wxString(startParam
, (*pp
)++ - startParam
);
1353 bool DocManager::ParseTeXFile(const wxString
& filename
)
1355 m_filename
= filename
;
1357 wxFile
file(m_filename
, wxFile::read
);
1358 if ( !file
.IsOpened() )
1361 off_t len
= file
.Length();
1362 if ( len
== wxInvalidOffset
)
1365 char *buf
= new char[len
+ 1];
1368 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1374 // reinit everything
1377 wxLogVerbose("%s: starting to parse doc file '%s'.",
1378 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1380 // the name of the class from the last "\membersection" command: we assume
1381 // that the following "\func" or "\constfunc" always documents a method of
1382 // this class (and it should always be like that in wxWindows documentation)
1385 for ( const char *current
= buf
; current
- buf
< len
; current
++ ) {
1386 // FIXME parsing is awfully inefficient
1388 if ( *current
== '%' ) {
1389 // comment, skip until the end of line
1391 SkipUntil(¤t
, '\n');
1396 // all the command we're interested in start with '\\'
1397 while ( *current
!= '\\' && *current
!= '\0' ) {
1398 if ( *current
++ == '\n' )
1402 if ( *current
== '\0' ) {
1403 // no more TeX commands left
1407 current
++; // skip '\\'
1415 } foundCommand
= Nothing
;
1417 size_t lenMatch
= TryMatch(current
, "func");
1419 foundCommand
= Func
;
1422 lenMatch
= TryMatch(current
, "constfunc");
1424 foundCommand
= ConstFunc
;
1426 lenMatch
= TryMatch(current
, "membersection");
1429 foundCommand
= MemberSect
;
1433 if ( foundCommand
== Nothing
)
1436 current
+= lenMatch
;
1438 if ( !SkipSpaceUntil(¤t
, '{') ) {
1439 wxLogWarning("file %s(%d): '{' expected after \\func, "
1440 "\\constfunc or \\membersection.",
1441 m_filename
.c_str(), m_line
);
1448 if ( foundCommand
== MemberSect
) {
1449 // what follows has the form <classname>::<funcname>
1450 const char *startClass
= current
;
1451 if ( !SkipUntil(¤t
, ':') || *(current
+ 1) != ':' ) {
1452 wxLogWarning("file %s(%d): '::' expected after "
1453 "\\membersection.", m_filename
.c_str(), m_line
);
1456 classname
= wxString(startClass
, current
- startClass
);
1457 TeXUnfilter(&classname
);
1463 // extract the return type
1464 const char *startRetType
= current
;
1466 if ( !SkipUntil(¤t
, '}') ) {
1467 wxLogWarning("file %s(%d): '}' expected after return type",
1468 m_filename
.c_str(), m_line
);
1473 wxString returnType
= wxString(startRetType
, current
- startRetType
);
1474 TeXUnfilter(&returnType
);
1477 if ( !SkipSpaceUntil(¤t
, '{') ) {
1478 wxLogWarning("file %s(%d): '{' expected after return type",
1479 m_filename
.c_str(), m_line
);
1485 const char *funcEnd
= current
;
1486 if ( !SkipUntil(&funcEnd
, '}') ) {
1487 wxLogWarning("file %s(%d): '}' expected after function name",
1488 m_filename
.c_str(), m_line
);
1493 wxString funcName
= wxString(current
, funcEnd
- current
);
1494 current
= funcEnd
+ 1;
1496 // trim spaces from both sides
1497 funcName
.Trim(FALSE
);
1498 funcName
.Trim(TRUE
);
1500 // special cases: '$...$' may be used for LaTeX inline math, remove the
1502 if ( funcName
.Find('$') != wxNOT_FOUND
) {
1504 for ( const char *p
= funcName
.c_str(); *p
!= '\0'; p
++ ) {
1505 if ( *p
!= '$' && !isspace(*p
) )
1512 // \destruct{foo} is really ~foo
1513 if ( funcName
[0u] == '\\' ) {
1514 size_t len
= strlen("\\destruct{");
1515 if ( funcName(0, len
) != "\\destruct{" ) {
1516 wxLogWarning("file %s(%d): \\destruct expected",
1517 m_filename
.c_str(), m_line
);
1522 funcName
.erase(0, len
);
1523 funcName
.Prepend('~');
1525 if ( !SkipSpaceUntil(¤t
, '}') ) {
1526 wxLogWarning("file %s(%d): '}' expected after destructor",
1527 m_filename
.c_str(), m_line
);
1532 funcEnd
++; // there is an extra '}' to count
1535 TeXUnfilter(&funcName
);
1538 current
= funcEnd
+ 1; // skip '}'
1539 if ( !SkipSpaceUntil(¤t
, '{') ||
1540 (current
++, !SkipSpaceUntil(¤t
, '\\')) ) {
1541 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1542 m_filename
.c_str(), m_line
);
1547 wxArrayString paramNames
, paramTypes
, paramValues
;
1549 bool isVararg
= FALSE
;
1551 current
++; // skip '\\'
1552 lenMatch
= TryMatch(current
, "void");
1554 lenMatch
= TryMatch(current
, "param");
1555 while ( lenMatch
&& (current
- buf
< len
) ) {
1556 current
+= lenMatch
;
1558 // now come {paramtype}{paramname}
1559 wxString paramType
= ExtractStringBetweenBraces(¤t
);
1560 if ( !!paramType
) {
1561 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1562 if ( !!paramText
) {
1563 // the param declaration may contain default value
1564 wxString paramName
= paramText
.BeforeFirst('='),
1565 paramValue
= paramText
.AfterFirst('=');
1567 // sanitize all strings
1568 TeXUnfilter(¶mValue
);
1569 TeXUnfilter(¶mName
);
1570 TeXUnfilter(¶mType
);
1572 paramValues
.Add(paramValue
);
1573 paramNames
.Add(paramName
);
1574 paramTypes
.Add(paramType
);
1579 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1580 if ( paramText
== "..." ) {
1584 wxLogWarning("Parameters of '%s::%s' are in "
1586 classname
.c_str(), funcName
.c_str());
1591 current
= SkipSpaces(current
);
1592 if ( *current
== ',' || *current
== '}' ) {
1593 current
= SkipSpaces(++current
);
1595 lenMatch
= TryMatch(current
, "\\param");
1598 wxLogWarning("file %s(%d): ',' or '}' expected after "
1599 "'\\param'", m_filename
.c_str(), m_line
);
1605 // if we got here there was no '\\void', so must have some params
1606 if ( paramNames
.IsEmpty() ) {
1607 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1608 m_filename
.c_str(), m_line
);
1614 // verbose diagnostic output
1616 size_t param
, paramCount
= paramNames
.GetCount();
1617 for ( param
= 0; param
< paramCount
; param
++ ) {
1622 paramsAll
<< paramTypes
[param
] << ' ' << paramNames
[param
];
1625 wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
1626 m_filename
.c_str(), m_line
,
1631 foundCommand
== ConstFunc
? " const" : "");
1633 // store the info about the just found function
1634 ArrayMethodInfo
*methods
;
1635 int index
= m_classes
.Index(classname
);
1636 if ( index
== wxNOT_FOUND
) {
1637 m_classes
.Add(classname
);
1639 methods
= new ArrayMethodInfo
;
1640 m_methods
.Add(methods
);
1643 methods
= m_methods
[(size_t)index
];
1646 ArrayParamInfo params
;
1647 for ( param
= 0; param
< paramCount
; param
++ ) {
1648 params
.Add(new ParamInfo(paramTypes
[param
],
1650 paramValues
[param
]));
1653 MethodInfo
*method
= new MethodInfo(returnType
, funcName
, params
);
1654 if ( foundCommand
== ConstFunc
)
1655 method
->SetFlag(MethodInfo::Const
);
1657 method
->SetFlag(MethodInfo::Vararg
);
1659 methods
->Add(method
);
1664 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1665 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1670 bool DocManager::DumpDifferences(spContext
*ctxTop
) const
1672 typedef MMemberListT::const_iterator MemberIndex
;
1674 bool foundDiff
= FALSE
;
1676 // flag telling us whether the given class was found at all in the header
1677 size_t nClass
, countClassesInDocs
= m_classes
.GetCount();
1678 bool *classExists
= new bool[countClassesInDocs
];
1679 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1680 classExists
[nClass
] = FALSE
;
1683 // ctxTop is normally an spFile
1684 wxASSERT( ctxTop
->GetContextType() == SP_CTX_FILE
);
1686 const MMemberListT
& classes
= ctxTop
->GetMembers();
1687 for ( MemberIndex i
= classes
.begin(); i
!= classes
.end(); i
++ ) {
1688 spContext
*ctx
= *i
;
1689 if ( ctx
->GetContextType() != SP_CTX_CLASS
) {
1690 // TODO process also global functions, macros, ...
1694 spClass
*ctxClass
= (spClass
*)ctx
;
1695 const wxString
& nameClass
= ctxClass
->mName
;
1696 int index
= m_classes
.Index(nameClass
);
1697 if ( index
== wxNOT_FOUND
) {
1698 if ( !m_ignoreNames
.IgnoreClass(nameClass
) ) {
1701 wxLogError("Class '%s' is not documented at all.",
1705 // it makes no sense to check for its functions
1709 classExists
[index
] = TRUE
;
1712 // array of method descriptions for this class
1713 const ArrayMethodInfo
& methods
= *(m_methods
[index
]);
1714 size_t nMethod
, countMethods
= methods
.GetCount();
1716 // flags telling if we already processed given function
1717 bool *methodExists
= new bool[countMethods
];
1718 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1719 methodExists
[nMethod
] = FALSE
;
1722 wxArrayString aOverloadedMethods
;
1724 const MMemberListT
& functions
= ctxClass
->GetMembers();
1725 for ( MemberIndex j
= functions
.begin(); j
!= functions
.end(); j
++ ) {
1727 if ( ctx
->GetContextType() != SP_CTX_OPERATION
)
1730 spOperation
*ctxMethod
= (spOperation
*)ctx
;
1731 const wxString
& nameMethod
= ctxMethod
->mName
;
1733 // find all functions with the same name
1734 wxArrayInt aMethodsWithSameName
;
1735 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1736 if ( methods
[nMethod
]->GetName() == nameMethod
)
1737 aMethodsWithSameName
.Add(nMethod
);
1740 if ( aMethodsWithSameName
.IsEmpty() && ctxMethod
->IsPublic() ) {
1741 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1744 wxLogError("'%s::%s' is not documented.",
1746 nameMethod
.c_str());
1749 // don't check params
1752 else if ( aMethodsWithSameName
.GetCount() == 1 ) {
1753 index
= (size_t)aMethodsWithSameName
[0u];
1754 methodExists
[index
] = TRUE
;
1756 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1759 if ( !ctxMethod
->IsPublic() ) {
1760 wxLogWarning("'%s::%s' is documented but not public.",
1762 nameMethod
.c_str());
1765 // check that the flags match
1766 const MethodInfo
& method
= *(methods
[index
]);
1768 bool isVirtual
= ctxMethod
->mIsVirtual
;
1769 if ( isVirtual
!= method
.HasFlag(MethodInfo::Virtual
) ) {
1770 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1774 isVirtual
? "not " : "");
1777 bool isConst
= ctxMethod
->mIsConstant
;
1778 if ( isConst
!= method
.HasFlag(MethodInfo::Const
) ) {
1779 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1783 isConst
? "not " : "");
1786 // check that the params match
1787 const MMemberListT
& params
= ctxMethod
->GetMembers();
1789 if ( params
.size() != method
.GetParamCount() ) {
1790 wxLogError("Incorrect number of parameters for '%s::%s' "
1791 "in the docs: should be %d instead of %d.",
1794 params
.size(), method
.GetParamCount());
1798 for ( MemberIndex k
= params
.begin();
1803 // what else can a function have?
1804 wxASSERT( ctx
->GetContextType() == SP_CTX_PARAMETER
);
1806 spParameter
*ctxParam
= (spParameter
*)ctx
;
1807 const ParamInfo
& param
= method
.GetParam(nParam
);
1808 if ( m_checkParamNames
&&
1809 (param
.GetName() != ctxParam
->mName
) ) {
1812 wxLogError("Parameter #%d of '%s::%s' should be "
1813 "'%s' and not '%s'.",
1817 ctxParam
->mName
.c_str(),
1818 param
.GetName().c_str());
1823 if ( param
.GetType() != ctxParam
->mType
) {
1826 wxLogError("Type of parameter '%s' of '%s::%s' "
1827 "should be '%s' and not '%s'.",
1828 ctxParam
->mName
.c_str(),
1831 ctxParam
->mType
.c_str(),
1832 param
.GetType().GetName().c_str());
1837 if ( param
.GetDefValue() != ctxParam
->mInitVal
) {
1838 wxLogWarning("Default value of parameter '%s' of "
1839 "'%s::%s' should be '%s' and not "
1841 ctxParam
->mName
.c_str(),
1844 ctxParam
->mInitVal
.c_str(),
1845 param
.GetDefValue().c_str());
1851 // TODO OVER add real support for overloaded methods
1853 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1856 if ( aOverloadedMethods
.Index(nameMethod
) == wxNOT_FOUND
) {
1857 // mark all methods with this name as existing
1858 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1859 if ( methods
[nMethod
]->GetName() == nameMethod
)
1860 methodExists
[nMethod
] = TRUE
;
1863 aOverloadedMethods
.Add(nameMethod
);
1865 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1866 "stupid to find the right match - skipping "
1867 "the param and flags checks.",
1869 nameMethod
.c_str());
1871 //else: warning already given
1875 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1876 if ( !methodExists
[nMethod
] ) {
1877 const wxString
& nameMethod
= methods
[nMethod
]->GetName();
1878 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1881 wxLogError("'%s::%s' is documented but doesn't exist.",
1883 nameMethod
.c_str());
1888 delete [] methodExists
;
1891 // check that all classes we found in the docs really exist
1892 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1893 if ( !classExists
[nClass
] ) {
1896 wxLogError("Class '%s' is documented but doesn't exist.",
1897 m_classes
[nClass
].c_str());
1901 delete [] classExists
;
1906 DocManager::~DocManager()
1908 WX_CLEAR_ARRAY(m_methods
);
1911 // ---------------------------------------------------------------------------
1912 // IgnoreNamesHandler implementation
1913 // ---------------------------------------------------------------------------
1915 int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry
*first
,
1916 IgnoreListEntry
*second
)
1918 // first compare the classes
1919 int rc
= first
->m_classname
.Cmp(second
->m_classname
);
1921 rc
= first
->m_funcname
.Cmp(second
->m_funcname
);
1926 bool IgnoreNamesHandler::AddNamesFromFile(const wxString
& filename
)
1928 wxFile
file(filename
, wxFile::read
);
1929 if ( !file
.IsOpened() )
1932 off_t len
= file
.Length();
1933 if ( len
== wxInvalidOffset
)
1936 char *buf
= new char[len
+ 1];
1939 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1946 for ( const char *current
= buf
; ; current
++ ) {
1948 // skip DOS line separator
1949 if ( *current
== '\r' )
1953 if ( *current
== '\n' || *current
== '\0' ) {
1954 if ( line
[0u] != '#' ) {
1955 if ( line
.Find(':') != wxNOT_FOUND
) {
1956 wxString classname
= line
.BeforeFirst(':'),
1957 funcname
= line
.AfterLast(':');
1958 m_ignore
.Add(new IgnoreListEntry(classname
, funcname
));
1962 m_ignore
.Add(new IgnoreListEntry(line
, ""));
1967 if ( *current
== '\0' )
1982 // -----------------------------------------------------------------------------
1983 // global function implementation
1984 // -----------------------------------------------------------------------------
1986 static wxString
MakeLabel(const char *classname
, const char *funcname
)
1988 wxString
label(classname
);
1989 if ( funcname
&& funcname
[0] == '\\' ) {
1990 // we may have some special TeX macro - so far only \destruct exists,
1991 // but may be later others will be added
1992 static const char *macros
[] = { "destruct" };
1993 static const char *replacement
[] = { "dtor" };
1996 for ( n
= 0; n
< WXSIZEOF(macros
); n
++ ) {
1997 if ( strncmp(funcname
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) {
2003 if ( n
== WXSIZEOF(macros
) ) {
2004 wxLogWarning("unknown function name '%s' - leaving as is.",
2008 funcname
= replacement
[n
];
2013 // special treatment for operatorXXX() stuff because the C operators
2014 // are not valid in LaTeX labels
2016 if ( wxString(funcname
).StartsWith("operator", &oper
) ) {
2017 label
<< "operator";
2030 for ( n
= 0; n
< WXSIZEOF(operatorNames
); n
++ ) {
2031 if ( oper
== operatorNames
[n
].oper
) {
2032 label
<< operatorNames
[n
].name
;
2038 if ( n
== WXSIZEOF(operatorNames
) ) {
2039 wxLogWarning("unknown operator '%s' - making dummy label.",
2045 else // simply use the func name
2056 static wxString
MakeHelpref(const char *argument
)
2059 helpref
<< "\\helpref{" << argument
<< "}{" << MakeLabel(argument
) << '}';
2064 static void TeXFilter(wxString
* str
)
2066 // TeX special which can be quoted (don't include backslash nor braces as
2068 static wxRegEx
reNonSpecialSpecials("[#$%&_]"),
2072 reNonSpecialSpecials
.ReplaceAll(str
, "\\\\\\0");
2074 // can't quote these ones as they produce accents when preceded by
2075 // backslash, so put them inside verb
2076 reAccents
.ReplaceAll(str
, "\\\\verb|\\0|");
2079 static void TeXUnfilter(wxString
* str
)
2081 // FIXME may be done much more quickly
2086 static wxRegEx
reNonSpecialSpecials("\\\\([#$%&_{}])"),
2087 reAccents("\\\\verb|([~^])|");
2089 reNonSpecialSpecials
.ReplaceAll(str
, "\\1");
2090 reAccents
.ReplaceAll(str
, "\\1");
2093 static wxString
GetAllComments(const spContext
& ctx
)
2096 const MCommentListT
& commentsList
= ctx
.GetCommentList();
2097 for ( MCommentListT::const_iterator i
= commentsList
.begin();
2098 i
!= commentsList
.end();
2100 wxString comment
= (*i
)->GetText();
2102 // don't take comments like "// ----------" &c
2103 comment
.Trim(FALSE
);
2105 comment
== wxString(comment
[0u], comment
.length() - 1) + '\n' )
2108 comments
<< comment
;
2114 static const char *GetCurrentTime(const char *timeFormat
)
2116 static char s_timeBuffer
[128];
2121 ptmNow
= localtime(&timeNow
);
2123 strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
);
2125 return s_timeBuffer
;
2128 static const wxString
GetVersionString()
2130 wxString version
= "$Revision$";
2131 wxRegEx("^\\$Revision$$").ReplaceFirst(&version
, "\\1");
2137 Revision 1.17 2001/11/30 21:43:35 VZ
2138 now the methods are sorted in the correct order in the generated docs
2140 Revision 1.16 2001/11/28 19:27:33 VZ
2141 HelpGen doesn't work in GUI mode
2143 Revision 1.15 2001/11/22 21:59:58 GD
2144 use "..." instead of <...> for wx headers
2146 Revision 1.14 2001/07/19 13:51:29 VZ
2147 fixes to version string
2149 Revision 1.13 2001/07/19 13:44:57 VZ
2150 1. compilation fixes
2151 2. don't quote special characters inside verbatim environment
2153 Revision 1.12 2000/10/09 13:53:33 juliansmart
2155 Doc corrections; added HelpGen project files
2157 Revision 1.11 2000/07/15 19:50:42 cvsuser
2160 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
2161 don't trasnform output dir name to lower case
2163 Revision 1.10 2000/03/11 10:05:23 VS
2164 now compiles with wxBase
2166 Revision 1.9 2000/01/16 13:25:21 VS
2167 compilation fixes (gcc)
2169 Revision 1.8 1999/09/13 14:29:39 JS
2171 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2172 into src for simplicity; added VC++ 5 project file
2174 Revision 1.7 1999/02/21 22:32:32 VZ
2175 1. more C++ parser fixes - now it almost parses wx/string.h
2176 a) #if/#ifdef/#else (very) limited support
2177 b) param type fix - now indirection chars are correctly handled
2178 c) class/struct/union distinction
2179 d) public/private fixes
2180 e) Dump() function added - very useful for debugging
2182 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2183 by default, and this option switches it on)
2185 Revision 1.6 1999/02/20 23:00:26 VZ
2186 1. new 'diff' mode which seems to work
2187 2. output files are not overwritten in 'dmup' mode
2188 3. fixes for better handling of const functions and operators
2189 ----------------------------
2191 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2192 1. Parser improvements
2193 a) const and virtual methods are parsed correctly (not static yet)
2194 b) "const" which is part of the return type is not swallowed
2196 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2197 "//---------" kind comments discarded now.
2198 ----------------------------
2200 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2202 some tweaks to HelpGen
2203 ----------------------------
2205 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2207 HelpGen starting to compile with VC++
2208 ----------------------------
2210 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2212 supports typedefs, generates "See also:" and adds "virtual " for virtual
2214 ----------------------------
2216 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2218 HelpGen is a prototype of the tool for automatic generation of the .tex files
2219 for wxWindows documentation from C++ headers
2222 /* vi: set tw=80 et ts=4 sw=4: */