1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Main program file for HelpGen
4 // Author: Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Copyright: (c) 1999 VZ
10 /////////////////////////////////////////////////////////////////////////////
15 1. wx/string.h confuses C++ parser terribly
16 2. C++ parser doesn't know about virtual functions, nor static ones
17 3. param checking is not done for vararg functions
18 4. type comparison is dumb: it doesn't know that "char *" is the same
19 that "char []" nor that "const char *" is the same as "char const *"
21 TODO (+ means fixed), see also the change log at the end of the file.
23 (i) small fixes in the current version
25 +1. Quote special TeX characters like '&' and '_' (=> derive from wxFile)
27 3. Document global variables
30 6. Include file name/line number in the "diff" messages?
31 +7. Support for vararg functions
33 (ii) plans for version 2
34 1. Use wxTextFile for direct file access to avoid one scan method problems
35 2. Use command line parser class for the options
36 3. support for overloaded functions in diff mode (search for OVER)
38 (iii) plans for version 3
39 1. Merging with existing files
43 // =============================================================================
45 // =============================================================================
47 // -----------------------------------------------------------------------------
49 // -----------------------------------------------------------------------------
52 #include "wx/wxprec.h"
55 #include <wx/string.h>
57 #include <wx/dynarray.h>
64 // C++ parsing classes
71 // argh, Windows defines this
76 // -----------------------------------------------------------------------------
78 // -----------------------------------------------------------------------------
80 class HelpGenApp
: public wxApp
85 // don't let wxWin parse our cmd line, we do it ourselves
86 virtual bool OnInit() { return TRUE
; }
91 IMPLEMENT_APP(HelpGenApp
);
93 // -----------------------------------------------------------------------------
95 // -----------------------------------------------------------------------------
97 // return the label for the given function name (i.e. argument of \label)
98 static wxString
MakeLabel(const char *classname
, const char *funcname
= NULL
);
100 // return the whole \helpref{arg}{arg_label} string
101 static wxString
MakeHelpref(const char *argument
);
103 // [un]quote special TeX characters (in place)
104 static void TeXFilter(wxString
* str
);
105 static void TeXUnfilter(wxString
* str
); // also trims spaces
107 // get all comments associated with this context
108 static wxString
GetAllComments(const spContext
& ctx
);
110 // get the string with current time (returns pointer to static buffer)
111 // timeFormat is used for the call of strftime(3)
112 static const char *GetCurrentTime(const char *timeFormat
);
114 // get the string containing the program version
115 static const wxString
GetVersionString();
117 // -----------------------------------------------------------------------------
119 // -----------------------------------------------------------------------------
121 // add a function which sanitazes the string before writing it to the file
122 class wxTeXFile
: public wxFile
127 // write a string to file verbatim (should only be used for the strings
128 // inside verbatim environment)
129 bool WriteVerbatim(const wxString
& s
)
131 return wxFile::Write(s
);
134 // write a string quoting TeX specials in it
135 bool WriteTeX(const wxString
& s
)
140 return wxFile::Write(t
);
144 wxTeXFile(const wxTeXFile
&);
145 wxTeXFile
& operator=(const wxTeXFile
&);
148 // helper class which manages the classes and function names to ignore for
149 // the documentation purposes (used by both HelpGenVisitor and DocManager)
150 class IgnoreNamesHandler
153 IgnoreNamesHandler() : m_ignore(CompareIgnoreListEntries
) { }
154 ~IgnoreNamesHandler() { WX_CLEAR_ARRAY(m_ignore
); }
156 // load file with classes/functions to ignore (add them to the names we
158 bool AddNamesFromFile(const wxString
& filename
);
160 // return TRUE if we ignore this function
161 bool IgnoreMethod(const wxString
& classname
,
162 const wxString
& funcname
) const
164 if ( IgnoreClass(classname
) )
167 IgnoreListEntry
ignore(classname
, funcname
);
169 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
172 // return TRUE if we ignore this class entirely
173 bool IgnoreClass(const wxString
& classname
) const
175 IgnoreListEntry
ignore(classname
, "");
177 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
181 struct IgnoreListEntry
183 IgnoreListEntry(const wxString
& classname
,
184 const wxString
& funcname
)
185 : m_classname(classname
), m_funcname(funcname
)
189 wxString m_classname
;
190 wxString m_funcname
; // if empty, ignore class entirely
193 static int CompareIgnoreListEntries(IgnoreListEntry
*first
,
194 IgnoreListEntry
*second
);
196 // for efficiency, let's sort it
197 WX_DEFINE_SORTED_ARRAY(IgnoreListEntry
*, ArrayNamesToIgnore
);
199 ArrayNamesToIgnore m_ignore
;
202 IgnoreNamesHandler(const IgnoreNamesHandler
&);
203 IgnoreNamesHandler
& operator=(const IgnoreNamesHandler
&);
206 // visitor implementation which writes all collected data to a .tex file
207 class HelpGenVisitor
: public spVisitor
211 HelpGenVisitor(const wxString
& directoryOut
, bool overwrite
);
213 virtual void VisitFile( spFile
& fl
);
214 virtual void VisitClass( spClass
& cl
);
215 virtual void VisitEnumeration( spEnumeration
& en
);
216 virtual void VisitTypeDef( spTypeDef
& td
);
217 virtual void VisitPreprocessorLine( spPreprocessorLine
& pd
);
218 virtual void VisitAttribute( spAttribute
& attr
);
219 virtual void VisitOperation( spOperation
& op
);
220 virtual void VisitParameter( spParameter
& param
);
224 // get our `ignore' object
225 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
227 // shut up g++ warning (ain't it stupid?)
228 virtual ~HelpGenVisitor() { }
231 // (re)initialize the state
234 // insert documentation for enums/typedefs coming immediately before the
235 // class declaration into the class documentation
236 void InsertTypedefDocs();
237 void InsertEnumDocs();
239 // write the headers for corresponding sections (only once)
240 void InsertDataStructuresHeader();
241 void InsertMethodsHeader();
243 // terminate the function documentation if it was started
244 void CloseFunction();
246 wxString m_directoryOut
, // directory for the output
247 m_fileHeader
; // name of the .h file we parse
248 bool m_overwrite
; // overwrite existing files?
249 wxTeXFile m_file
; // file we're writing to now
252 bool m_inClass
, // TRUE after file successfully opened
253 m_inTypesSection
, // enums & typedefs go there
254 m_inMethodSection
, // functions go here
255 m_isFirstParam
, // first parameter of current function?
256 m_inFunction
; // we're parsing a function declaration
258 // holders for "saved" documentation
259 wxString m_textStoredTypedefs
,
260 m_textStoredFunctionComment
;
262 // for enums we have to use an array as we can't intermix the normal text
263 // and the text inside verbatim environment
264 wxArrayString m_storedEnums
,
267 // headers included by this file
268 wxArrayString m_headers
;
270 // ignore handler: tells us which classes to ignore for doc generation
272 IgnoreNamesHandler m_ignoreNames
;
275 HelpGenVisitor(const HelpGenVisitor
&);
276 HelpGenVisitor
& operator=(const HelpGenVisitor
&);
279 // documentation manager - a class which parses TeX files and remembers the
280 // functions documented in them and can later compare them with all functions
281 // found under ctxTop by C++ parser
285 DocManager(bool checkParamNames
);
288 // returns FALSE on failure
289 bool ParseTeXFile(const wxString
& filename
);
291 // returns FALSE if there were any differences
292 bool DumpDifferences(spContext
*ctxTop
) const;
294 // get our `ignore' object
295 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
301 // returns the length of 'match' if the string 'str' starts with it or 0
303 static size_t TryMatch(const char *str
, const char *match
);
305 // skip spaces: returns pointer to first non space character (also
306 // updates the value of m_line)
307 const char *SkipSpaces(const char *p
)
309 while ( isspace(*p
) ) {
317 // skips characters until the next 'c' in '*pp' unless it ends before in
318 // which case FALSE is returned and pp points to '\0', otherwise TRUE is
319 // returned and pp points to 'c'
320 bool SkipUntil(const char **pp
, char c
);
322 // the same as SkipUntil() but only spaces are skipped: on first non space
323 // character different from 'c' the function stops and returns FALSE
324 bool SkipSpaceUntil(const char **pp
, char c
);
326 // extract the string between {} and modify '*pp' to point at the
327 // character immediately after the closing '}'. The returned string is empty
329 wxString
ExtractStringBetweenBraces(const char **pp
);
331 // the current file and line while we're in ParseTeXFile (for error
336 // functions and classes to ignore during diff
337 // -------------------------------------------
339 IgnoreNamesHandler m_ignoreNames
;
341 // information about all functions documented in the TeX file(s)
342 // -------------------------------------------------------------
344 // info about a type: for now stored as text string, but must be parsed
345 // further later (to know that "char *" == "char []" - TODO)
349 TypeInfo(const wxString
& type
) : m_type(type
) { }
351 bool operator==(const wxString
& type
) const { return m_type
== type
; }
352 bool operator!=(const wxString
& type
) const { return m_type
!= type
; }
354 const wxString
& GetName() const { return m_type
; }
360 // info abotu a function parameter
364 ParamInfo(const wxString
& type
,
365 const wxString
& name
,
366 const wxString
& value
)
367 : m_type(type
), m_name(name
), m_value(value
)
371 const TypeInfo
& GetType() const { return m_type
; }
372 const wxString
& GetName() const { return m_name
; }
373 const wxString
& GetDefValue() const { return m_value
; }
376 TypeInfo m_type
; // type of parameter
377 wxString m_name
; // name
378 wxString m_value
; // default value
381 WX_DEFINE_ARRAY(ParamInfo
*, ArrayParamInfo
);
383 // info about a function
396 MethodInfo(const wxString
& type
,
397 const wxString
& name
,
398 const ArrayParamInfo
& params
)
399 : m_typeRet(type
), m_name(name
), m_params(params
)
404 void SetFlag(MethodFlags flag
) { m_flags
|= flag
; }
406 const TypeInfo
& GetType() const { return m_typeRet
; }
407 const wxString
& GetName() const { return m_name
; }
408 const ParamInfo
& GetParam(size_t n
) const { return *(m_params
[n
]); }
409 size_t GetParamCount() const { return m_params
.GetCount(); }
411 bool HasFlag(MethodFlags flag
) const { return (m_flags
& flag
) != 0; }
413 ~MethodInfo() { WX_CLEAR_ARRAY(m_params
); }
416 TypeInfo m_typeRet
; // return type
418 int m_flags
; // bit mask of the value from the enum above
420 ArrayParamInfo m_params
;
423 WX_DEFINE_ARRAY(MethodInfo
*, ArrayMethodInfo
);
424 WX_DEFINE_ARRAY(ArrayMethodInfo
*, ArrayMethodInfos
);
426 // first array contains the names of all classes we found, the second has a
427 // pointer to the array of methods of the given class at the same index as
428 // the class name appears in m_classes
429 wxArrayString m_classes
;
430 ArrayMethodInfos m_methods
;
432 // are we checking parameter names?
433 bool m_checkParamNames
;
436 DocManager(const DocManager
&);
437 DocManager
& operator=(const DocManager
&);
440 // -----------------------------------------------------------------------------
442 // -----------------------------------------------------------------------------
444 // =============================================================================
446 // =============================================================================
448 // this function never returns
451 wxString prog
= wxTheApp
->argv
[0];
452 wxString basename
= prog
.AfterLast('/');
455 basename
= prog
.AfterLast('\\');
461 "usage: %s [global options] <mode> [mode options] <files...>\n"
463 " where global options are:\n"
466 " -H give this usage message\n"
467 " -V print the version info\n"
468 " -i file file with classes/function to ignore\n"
470 " where mode is one of: dump, diff\n"
472 " dump means generate .tex files for TeX2RTF converter from specified\n"
473 " headers files, mode options are:\n"
474 " -f overwrite existing files\n"
475 " -o outdir directory for generated files\n"
477 " diff means compare the set of methods documented .tex file with the\n"
478 " methods declared in the header:\n"
479 " %s diff <file.h> <files.tex...>.\n"
480 " mode specific options are:\n"
481 " -p do check parameter names (not done by default)\n"
482 "\n", basename
.c_str(), basename
.c_str());
487 int HelpGenApp::OnRun()
500 wxArrayString filesH
, filesTeX
;
501 wxString directoryOut
, // directory for 'dmup' output
502 ignoreFile
; // file with classes/functions to ignore
503 bool overwrite
= FALSE
, // overwrite existing files during 'dump'?
504 paramNames
= FALSE
; // check param names during 'diff'?
506 for ( int current
= 1; current
< argc
; current
++ ) {
507 // all options have one letter
508 if ( argv
[current
][0] == '-' ) {
509 if ( argv
[current
][2] == '\0' ) {
510 switch ( argv
[current
][1] ) {
513 wxLog::GetActiveTarget()->SetVerbose();
518 wxLog::GetActiveTarget()->SetVerbose(FALSE
);
528 wxLogMessage("HelpGen version %s\n"
529 "(c) 1999-2001 Vadim Zeitlin\n",
530 GetVersionString().c_str());
535 if ( current
>= argc
) {
536 wxLogError("-i option requires an argument.");
541 ignoreFile
= argv
[current
];
545 if ( mode
!= Mode_Diff
) {
546 wxLogError("-p is only valid with diff.");
555 if ( mode
!= Mode_Dump
) {
556 wxLogError("-f is only valid with dump.");
565 if ( mode
!= Mode_Dump
) {
566 wxLogError("-o is only valid with dump.");
572 if ( current
>= argc
) {
573 wxLogError("-o option requires an argument.");
578 directoryOut
= argv
[current
];
579 if ( !!directoryOut
) {
580 // terminate with a '/' if it doesn't have it
581 switch ( directoryOut
.Last() ) {
592 //else: it's empty, do nothing
597 wxLogError("unknown option '%s'", argv
[current
]);
602 wxLogError("only one letter options are allowed, not '%s'.",
606 // only get here after a break from switch or from else branch of if
611 if ( mode
== Mode_None
) {
612 if ( strcmp(argv
[current
], "diff") == 0 )
614 else if ( strcmp(argv
[current
], "dump") == 0 )
617 wxLogError("unknown mode '%s'.", argv
[current
]);
623 if ( mode
== Mode_Dump
|| filesH
.IsEmpty() ) {
624 filesH
.Add(argv
[current
]);
627 // 2nd files and further are TeX files in diff mode
628 wxASSERT( mode
== Mode_Diff
);
630 filesTeX
.Add(argv
[current
]);
636 // create a parser object and a visitor derivation
637 CJSourceParser parser
;
638 HelpGenVisitor
visitor(directoryOut
, overwrite
);
639 if ( !!ignoreFile
&& mode
== Mode_Dump
)
640 visitor
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
642 spContext
*ctxTop
= NULL
;
644 // parse all header files
645 size_t nFiles
= filesH
.GetCount();
646 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
647 wxString header
= filesH
[n
];
648 ctxTop
= parser
.ParseFile(header
);
650 wxLogWarning("Header file '%s' couldn't be processed.",
653 else if ( mode
== Mode_Dump
) {
654 ((spFile
*)ctxTop
)->mFileName
= header
;
655 visitor
.VisitAll(*ctxTop
);
662 #endif // __WXDEBUG__
665 // parse all TeX files
666 if ( mode
== Mode_Diff
) {
668 wxLogError("Can't complete diff.");
674 DocManager
docman(paramNames
);
676 size_t nFiles
= filesTeX
.GetCount();
677 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
678 wxString file
= filesTeX
[n
];
679 if ( !docman
.ParseTeXFile(file
) ) {
680 wxLogWarning("TeX file '%s' couldn't be processed.",
686 docman
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
688 docman
.DumpDifferences(ctxTop
);
694 // -----------------------------------------------------------------------------
695 // HelpGenVisitor implementation
696 // -----------------------------------------------------------------------------
698 HelpGenVisitor::HelpGenVisitor(const wxString
& directoryOut
,
700 : m_directoryOut(directoryOut
)
702 m_overwrite
= overwrite
;
707 void HelpGenVisitor::Reset()
712 m_inMethodSection
= FALSE
;
714 m_textStoredTypedefs
=
715 m_textStoredFunctionComment
= "";
717 m_storedEnums
.Empty();
718 m_storedEnumsVerb
.Empty();
722 void HelpGenVisitor::InsertTypedefDocs()
724 m_file
.WriteTeX(m_textStoredTypedefs
);
725 m_textStoredTypedefs
.Empty();
728 void HelpGenVisitor::InsertEnumDocs()
730 size_t count
= m_storedEnums
.GetCount();
731 for ( size_t n
= 0; n
< count
; n
++ )
733 m_file
.WriteTeX(m_storedEnums
[n
]);
734 m_file
.WriteVerbatim(m_storedEnumsVerb
[n
] + '\n');
737 m_storedEnums
.Empty();
738 m_storedEnumsVerb
.Empty();
741 void HelpGenVisitor::InsertDataStructuresHeader()
743 if ( !m_inTypesSection
) {
744 m_inTypesSection
= TRUE
;
746 m_file
.Write("\\wxheading{Data structures}\n\n");
750 void HelpGenVisitor::InsertMethodsHeader()
752 if ( !m_inMethodSection
) {
753 m_inMethodSection
= TRUE
;
755 m_file
.Write( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
759 void HelpGenVisitor::CloseFunction()
761 if ( m_inFunction
) {
762 m_inFunction
= FALSE
;
765 if ( m_isFirstParam
) {
767 totalText
<< "\\void";
770 totalText
<< "}\n\n";
771 m_file
.Write(totalText
);
773 if ( !m_textStoredFunctionComment
.IsEmpty() )
774 m_file
.WriteTeX(m_textStoredFunctionComment
+ '\n');
778 void HelpGenVisitor::EndVisit()
782 m_fileHeader
.Empty();
784 wxLogVerbose("%s: finished generating for the current file.",
785 GetCurrentTime("%H:%M:%S"));
788 void HelpGenVisitor::VisitFile( spFile
& file
)
790 m_fileHeader
= file
.mFileName
;
791 wxLogVerbose("%s: started generating docs for classes from file '%s'...",
792 GetCurrentTime("%H:%M:%S"), m_fileHeader
.c_str());
795 void HelpGenVisitor::VisitClass( spClass
& cl
)
797 m_inClass
= FALSE
; // will be left FALSE on error
799 wxString name
= cl
.GetName();
801 if ( m_ignoreNames
.IgnoreClass(name
) ) {
802 wxLogVerbose("Skipping ignored class '%s'.", name
.c_str());
807 // the file name is built from the class name by removing the leading "wx"
808 // if any and converting it to the lower case
810 if ( name(0, 2) == "wx" ) {
811 filename
<< name
.c_str() + 2;
817 filename
.MakeLower();
819 filename
.Prepend(m_directoryOut
);
821 if ( !m_overwrite
&& wxFile::Exists(filename
) ) {
822 wxLogError("Won't overwrite existing file '%s' - please use '-f'.",
828 m_inClass
= m_file
.Open(filename
, wxFile::write
);
830 wxLogError("Can't generate documentation for the class '%s'.",
837 m_inTypesSection
= FALSE
;
839 wxLogInfo("Created new file '%s' for class '%s'.",
840 filename
.c_str(), name
.c_str());
842 // write out the header
845 "%% automatically generated by HelpGen %s from\n"
850 "\\section{\\class{%s}}\\label{%s}\n\n",
851 GetVersionString().c_str(),
852 m_fileHeader
.c_str(),
853 GetCurrentTime("%d/%b/%y %H:%M:%S"),
855 wxString(name
).MakeLower().c_str());
857 m_file
.Write(header
);
859 // the entire text we're writing to file
862 // if the header includes other headers they must be related to it... try to
863 // automatically generate the "See also" clause
864 if ( !m_headers
.IsEmpty() ) {
865 // correspondence between wxWindows headers and class names
866 static const char *headers
[] = {
875 // NULL here means not to insert anything in "See also" for the
876 // corresponding header
877 static const char *classes
[] = {
886 wxASSERT_MSG( WXSIZEOF(headers
) == WXSIZEOF(classes
),
887 "arrays must be in sync!" );
889 wxArrayInt interestingClasses
;
891 size_t count
= m_headers
.Count(), index
;
892 for ( size_t n
= 0; n
< count
; n
++ ) {
893 wxString baseHeaderName
= m_headers
[n
].Before('.');
894 if ( baseHeaderName(0, 3) != "wx/" )
897 baseHeaderName
.erase(0, 3);
898 for ( index
= 0; index
< WXSIZEOF(headers
); index
++ ) {
899 if ( Stricmp(baseHeaderName
, headers
[index
]) == 0 )
903 if ( (index
< WXSIZEOF(headers
)) && classes
[index
] ) {
904 // interesting header
905 interestingClasses
.Add(index
);
909 if ( !interestingClasses
.IsEmpty() ) {
910 // do generate "See also" clause
911 totalText
<< "\\wxheading{See also:}\n\n";
913 count
= interestingClasses
.Count();
914 for ( index
= 0; index
< count
; index
++ ) {
918 totalText
<< MakeHelpref(classes
[interestingClasses
[index
]]);
925 // the comment before the class generally explains what is it for so put it
926 // in place of the class description
927 if ( cl
.HasComments() ) {
928 wxString comment
= GetAllComments(cl
);
930 totalText
<< '\n' << comment
<< '\n';
933 // derived from section
934 wxString derived
= "\\wxheading{Derived from}\n\n";
936 const StrListT
& baseClasses
= cl
.mSuperClassNames
;
937 if ( baseClasses
.size() == 0 ) {
938 derived
<< "No base class";
942 for ( StrListT::const_iterator i
= baseClasses
.begin();
943 i
!= baseClasses
.end();
946 // separate from the previous one
953 wxString baseclass
= *i
;
954 derived
<< "\\helpref{" << baseclass
<< "}";
955 derived
<< "{" << baseclass
.MakeLower() << "}";
958 totalText
<< derived
<< "\n\n";
960 // write all this to file
961 m_file
.WriteTeX(totalText
);
963 // if there were any enums/typedefs before, insert their documentation now
964 InsertDataStructuresHeader();
969 void HelpGenVisitor::VisitEnumeration( spEnumeration
& en
)
973 if ( m_inMethodSection
) {
974 // FIXME that's a bug, but tell the user aboit it nevertheless... we
975 // should be smart enough to process even the enums which come after the
977 wxLogWarning("enum '%s' ignored, please put it before the class "
978 "methods.", en
.GetName().c_str());
982 // simply copy the enum text in the docs
983 wxString enumeration
= GetAllComments(en
),
986 enumerationVerb
<< "\\begin{verbatim}\n"
988 << "\n\\end{verbatim}\n";
990 // remember for later use if we're not inside a class yet
992 m_storedEnums
.Add(enumeration
);
993 m_storedEnumsVerb
.Add(enumerationVerb
);
996 // write the header for this section if not done yet
997 InsertDataStructuresHeader();
999 m_file
.WriteTeX(enumeration
);
1000 m_file
.WriteVerbatim(enumerationVerb
);
1005 void HelpGenVisitor::VisitTypeDef( spTypeDef
& td
)
1009 if ( m_inMethodSection
) {
1010 // FIXME that's a bug, but tell the user aboit it nevertheless...
1011 wxLogWarning("typedef '%s' ignored, please put it before the class "
1012 "methods.", td
.GetName().c_str());
1016 wxString typedefdoc
;
1017 typedefdoc
<< "{\\small \\begin{verbatim}\n"
1018 << "typedef " << td
.mOriginalType
<< ' ' << td
.GetName()
1019 << "\n\\end{verbatim}}\n"
1020 << GetAllComments(td
);
1022 // remember for later use if we're not inside a class yet
1024 if ( !m_textStoredTypedefs
.IsEmpty() ) {
1025 m_textStoredTypedefs
<< '\n';
1028 m_textStoredTypedefs
<< typedefdoc
;
1031 // write the header for this section if not done yet
1032 InsertDataStructuresHeader();
1035 m_file
.WriteTeX(typedefdoc
);
1039 void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine
& pd
)
1041 switch ( pd
.GetStatementType() ) {
1042 case SP_PREP_DEF_INCLUDE_FILE
:
1043 m_headers
.Add(pd
.CPP_GetIncludedFileNeme());
1046 case SP_PREP_DEF_DEFINE_SYMBOL
:
1047 // TODO decide if it's a constant and document it if it is
1052 void HelpGenVisitor::VisitAttribute( spAttribute
& attr
)
1056 // only document the public member variables
1057 if ( !m_inClass
|| !attr
.IsPublic() )
1060 wxLogWarning("Ignoring member variable '%s'.", attr
.GetName().c_str());
1063 void HelpGenVisitor::VisitOperation( spOperation
& op
)
1068 // we don't generate docs right now - either we ignore this class
1069 // entirely or we couldn't open the file
1073 if ( !op
.IsInClass() ) {
1074 // TODO document global functions
1075 wxLogWarning("skipped global function '%s'.", op
.GetName().c_str());
1080 if ( op
.mVisibility
== SP_VIS_PRIVATE
) {
1081 // FIXME should we document protected functions?
1085 wxString funcname
= op
.GetName(),
1086 classname
= op
.GetClass().GetName();
1087 if ( m_ignoreNames
.IgnoreMethod(classname
, funcname
) ) {
1088 wxLogVerbose("Skipping ignored '%s::%s'.",
1089 classname
.c_str(), funcname
.c_str());
1094 InsertMethodsHeader();
1098 m_isFirstParam
= TRUE
;
1100 m_textStoredFunctionComment
= GetAllComments(op
);
1102 // start function documentation
1105 // check for the special case of dtor
1107 if ( (funcname
[0] == '~') && (classname
== funcname
.c_str() + 1) ) {
1108 dtor
.Printf("\\destruct{%s}", classname
.c_str());
1112 totalText
.Printf("\n"
1113 "\\membersection{%s::%s}\\label{%s}\n"
1115 "\\%sfunc{%s%s}{%s}{",
1116 classname
.c_str(), funcname
.c_str(),
1117 MakeLabel(classname
, funcname
).c_str(),
1118 op
.mIsConstant
? "const" : "",
1119 op
.mIsVirtual
? "virtual " : "",
1120 op
.mRetType
.c_str(),
1123 m_file
.WriteTeX(totalText
);
1126 void HelpGenVisitor::VisitParameter( spParameter
& param
)
1128 if ( !m_inFunction
)
1132 if ( m_isFirstParam
) {
1133 m_isFirstParam
= FALSE
;
1139 totalText
<< "\\param{" << param
.mType
<< " }{" << param
.GetName();
1140 wxString defvalue
= param
.mInitVal
;
1141 if ( !defvalue
.IsEmpty() ) {
1142 totalText
<< " = " << defvalue
;
1147 m_file
.WriteTeX(totalText
);
1150 // ---------------------------------------------------------------------------
1152 // ---------------------------------------------------------------------------
1154 DocManager::DocManager(bool checkParamNames
)
1156 m_checkParamNames
= checkParamNames
;
1159 size_t DocManager::TryMatch(const char *str
, const char *match
)
1161 size_t lenMatch
= 0;
1162 while ( str
[lenMatch
] == match
[lenMatch
] ) {
1165 if ( match
[lenMatch
] == '\0' )
1172 bool DocManager::SkipUntil(const char **pp
, char c
)
1174 const char *p
= *pp
;
1190 bool DocManager::SkipSpaceUntil(const char **pp
, char c
)
1192 const char *p
= *pp
;
1194 if ( !isspace(*p
) || *p
== '\0' )
1208 wxString
DocManager::ExtractStringBetweenBraces(const char **pp
)
1212 if ( !SkipSpaceUntil(pp
, '{') ) {
1213 wxLogWarning("file %s(%d): '{' expected after '\\param'",
1214 m_filename
.c_str(), m_line
);
1218 const char *startParam
= ++*pp
; // skip '{'
1220 if ( !SkipUntil(pp
, '}') ) {
1221 wxLogWarning("file %s(%d): '}' expected after '\\param'",
1222 m_filename
.c_str(), m_line
);
1225 result
= wxString(startParam
, (*pp
)++ - startParam
);
1232 bool DocManager::ParseTeXFile(const wxString
& filename
)
1234 m_filename
= filename
;
1236 wxFile
file(m_filename
, wxFile::read
);
1237 if ( !file
.IsOpened() )
1240 off_t len
= file
.Length();
1241 if ( len
== wxInvalidOffset
)
1244 char *buf
= new char[len
+ 1];
1247 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1253 // reinit everything
1256 wxLogVerbose("%s: starting to parse doc file '%s'.",
1257 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1259 // the name of the class from the last "\membersection" command: we assume
1260 // that the following "\func" or "\constfunc" always documents a method of
1261 // this class (and it should always be like that in wxWindows documentation)
1264 for ( const char *current
= buf
; current
- buf
< len
; current
++ ) {
1265 // FIXME parsing is awfully inefficient
1267 if ( *current
== '%' ) {
1268 // comment, skip until the end of line
1270 SkipUntil(¤t
, '\n');
1275 // all the command we're interested in start with '\\'
1276 while ( *current
!= '\\' && *current
!= '\0' ) {
1277 if ( *current
++ == '\n' )
1281 if ( *current
== '\0' ) {
1282 // no more TeX commands left
1286 current
++; // skip '\\'
1294 } foundCommand
= Nothing
;
1296 size_t lenMatch
= TryMatch(current
, "func");
1298 foundCommand
= Func
;
1301 lenMatch
= TryMatch(current
, "constfunc");
1303 foundCommand
= ConstFunc
;
1305 lenMatch
= TryMatch(current
, "membersection");
1308 foundCommand
= MemberSect
;
1312 if ( foundCommand
== Nothing
)
1315 current
+= lenMatch
;
1317 if ( !SkipSpaceUntil(¤t
, '{') ) {
1318 wxLogWarning("file %s(%d): '{' expected after \\func, "
1319 "\\constfunc or \\membersection.",
1320 m_filename
.c_str(), m_line
);
1327 if ( foundCommand
== MemberSect
) {
1328 // what follows has the form <classname>::<funcname>
1329 const char *startClass
= current
;
1330 if ( !SkipUntil(¤t
, ':') || *(current
+ 1) != ':' ) {
1331 wxLogWarning("file %s(%d): '::' expected after "
1332 "\\membersection.", m_filename
.c_str(), m_line
);
1335 classname
= wxString(startClass
, current
- startClass
);
1336 TeXUnfilter(&classname
);
1342 // extract the return type
1343 const char *startRetType
= current
;
1345 if ( !SkipUntil(¤t
, '}') ) {
1346 wxLogWarning("file %s(%d): '}' expected after return type",
1347 m_filename
.c_str(), m_line
);
1352 wxString returnType
= wxString(startRetType
, current
- startRetType
);
1353 TeXUnfilter(&returnType
);
1356 if ( !SkipSpaceUntil(¤t
, '{') ) {
1357 wxLogWarning("file %s(%d): '{' expected after return type",
1358 m_filename
.c_str(), m_line
);
1364 const char *funcEnd
= current
;
1365 if ( !SkipUntil(&funcEnd
, '}') ) {
1366 wxLogWarning("file %s(%d): '}' expected after function name",
1367 m_filename
.c_str(), m_line
);
1372 wxString funcName
= wxString(current
, funcEnd
- current
);
1373 current
= funcEnd
+ 1;
1375 // trim spaces from both sides
1376 funcName
.Trim(FALSE
);
1377 funcName
.Trim(TRUE
);
1379 // special cases: '$...$' may be used for LaTeX inline math, remove the
1381 if ( funcName
.Find('$') != wxNOT_FOUND
) {
1383 for ( const char *p
= funcName
.c_str(); *p
!= '\0'; p
++ ) {
1384 if ( *p
!= '$' && !isspace(*p
) )
1391 // \destruct{foo} is really ~foo
1392 if ( funcName
[0u] == '\\' ) {
1393 size_t len
= strlen("\\destruct{");
1394 if ( funcName(0, len
) != "\\destruct{" ) {
1395 wxLogWarning("file %s(%d): \\destruct expected",
1396 m_filename
.c_str(), m_line
);
1401 funcName
.erase(0, len
);
1402 funcName
.Prepend('~');
1404 if ( !SkipSpaceUntil(¤t
, '}') ) {
1405 wxLogWarning("file %s(%d): '}' expected after destructor",
1406 m_filename
.c_str(), m_line
);
1411 funcEnd
++; // there is an extra '}' to count
1414 TeXUnfilter(&funcName
);
1417 current
= funcEnd
+ 1; // skip '}'
1418 if ( !SkipSpaceUntil(¤t
, '{') ||
1419 (current
++, !SkipSpaceUntil(¤t
, '\\')) ) {
1420 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1421 m_filename
.c_str(), m_line
);
1426 wxArrayString paramNames
, paramTypes
, paramValues
;
1428 bool isVararg
= FALSE
;
1430 current
++; // skip '\\'
1431 lenMatch
= TryMatch(current
, "void");
1433 lenMatch
= TryMatch(current
, "param");
1434 while ( lenMatch
&& (current
- buf
< len
) ) {
1435 current
+= lenMatch
;
1437 // now come {paramtype}{paramname}
1438 wxString paramType
= ExtractStringBetweenBraces(¤t
);
1439 if ( !!paramType
) {
1440 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1441 if ( !!paramText
) {
1442 // the param declaration may contain default value
1443 wxString paramName
= paramText
.BeforeFirst('='),
1444 paramValue
= paramText
.AfterFirst('=');
1446 // sanitize all strings
1447 TeXUnfilter(¶mValue
);
1448 TeXUnfilter(¶mName
);
1449 TeXUnfilter(¶mType
);
1451 paramValues
.Add(paramValue
);
1452 paramNames
.Add(paramName
);
1453 paramTypes
.Add(paramType
);
1458 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1459 if ( paramText
== "..." ) {
1463 wxLogWarning("Parameters of '%s::%s' are in "
1465 classname
.c_str(), funcName
.c_str());
1470 current
= SkipSpaces(current
);
1471 if ( *current
== ',' || *current
== '}' ) {
1472 current
= SkipSpaces(++current
);
1474 lenMatch
= TryMatch(current
, "\\param");
1477 wxLogWarning("file %s(%d): ',' or '}' expected after "
1478 "'\\param'", m_filename
.c_str(), m_line
);
1484 // if we got here there was no '\\void', so must have some params
1485 if ( paramNames
.IsEmpty() ) {
1486 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1487 m_filename
.c_str(), m_line
);
1493 // verbose diagnostic output
1495 size_t param
, paramCount
= paramNames
.GetCount();
1496 for ( param
= 0; param
< paramCount
; param
++ ) {
1501 paramsAll
<< paramTypes
[param
] << ' ' << paramNames
[param
];
1504 wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
1505 m_filename
.c_str(), m_line
,
1510 foundCommand
== ConstFunc
? " const" : "");
1512 // store the info about the just found function
1513 ArrayMethodInfo
*methods
;
1514 int index
= m_classes
.Index(classname
);
1515 if ( index
== wxNOT_FOUND
) {
1516 m_classes
.Add(classname
);
1518 methods
= new ArrayMethodInfo
;
1519 m_methods
.Add(methods
);
1522 methods
= m_methods
[(size_t)index
];
1525 ArrayParamInfo params
;
1526 for ( param
= 0; param
< paramCount
; param
++ ) {
1527 params
.Add(new ParamInfo(paramTypes
[param
],
1529 paramValues
[param
]));
1532 MethodInfo
*method
= new MethodInfo(returnType
, funcName
, params
);
1533 if ( foundCommand
== ConstFunc
)
1534 method
->SetFlag(MethodInfo::Const
);
1536 method
->SetFlag(MethodInfo::Vararg
);
1538 methods
->Add(method
);
1543 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1544 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1549 bool DocManager::DumpDifferences(spContext
*ctxTop
) const
1551 typedef MMemberListT::const_iterator MemberIndex
;
1553 bool foundDiff
= FALSE
;
1555 // flag telling us whether the given class was found at all in the header
1556 size_t nClass
, countClassesInDocs
= m_classes
.GetCount();
1557 bool *classExists
= new bool[countClassesInDocs
];
1558 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1559 classExists
[nClass
] = FALSE
;
1562 // ctxTop is normally an spFile
1563 wxASSERT( ctxTop
->GetContextType() == SP_CTX_FILE
);
1565 const MMemberListT
& classes
= ctxTop
->GetMembers();
1566 for ( MemberIndex i
= classes
.begin(); i
!= classes
.end(); i
++ ) {
1567 spContext
*ctx
= *i
;
1568 if ( ctx
->GetContextType() != SP_CTX_CLASS
) {
1569 // TODO process also global functions, macros, ...
1573 spClass
*ctxClass
= (spClass
*)ctx
;
1574 const wxString
& nameClass
= ctxClass
->mName
;
1575 int index
= m_classes
.Index(nameClass
);
1576 if ( index
== wxNOT_FOUND
) {
1577 if ( !m_ignoreNames
.IgnoreClass(nameClass
) ) {
1580 wxLogError("Class '%s' is not documented at all.",
1584 // it makes no sense to check for its functions
1588 classExists
[index
] = TRUE
;
1591 // array of method descriptions for this class
1592 const ArrayMethodInfo
& methods
= *(m_methods
[index
]);
1593 size_t nMethod
, countMethods
= methods
.GetCount();
1595 // flags telling if we already processed given function
1596 bool *methodExists
= new bool[countMethods
];
1597 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1598 methodExists
[nMethod
] = FALSE
;
1601 wxArrayString aOverloadedMethods
;
1603 const MMemberListT
& functions
= ctxClass
->GetMembers();
1604 for ( MemberIndex j
= functions
.begin(); j
!= functions
.end(); j
++ ) {
1606 if ( ctx
->GetContextType() != SP_CTX_OPERATION
)
1609 spOperation
*ctxMethod
= (spOperation
*)ctx
;
1610 const wxString
& nameMethod
= ctxMethod
->mName
;
1612 // find all functions with the same name
1613 wxArrayInt aMethodsWithSameName
;
1614 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1615 if ( methods
[nMethod
]->GetName() == nameMethod
)
1616 aMethodsWithSameName
.Add(nMethod
);
1619 if ( aMethodsWithSameName
.IsEmpty() && ctxMethod
->IsPublic() ) {
1620 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1623 wxLogError("'%s::%s' is not documented.",
1625 nameMethod
.c_str());
1628 // don't check params
1631 else if ( aMethodsWithSameName
.GetCount() == 1 ) {
1632 index
= (size_t)aMethodsWithSameName
[0u];
1633 methodExists
[index
] = TRUE
;
1635 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1638 if ( !ctxMethod
->IsPublic() ) {
1639 wxLogWarning("'%s::%s' is documented but not public.",
1641 nameMethod
.c_str());
1644 // check that the flags match
1645 const MethodInfo
& method
= *(methods
[index
]);
1647 bool isVirtual
= ctxMethod
->mIsVirtual
;
1648 if ( isVirtual
!= method
.HasFlag(MethodInfo::Virtual
) ) {
1649 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1653 isVirtual
? "not " : "");
1656 bool isConst
= ctxMethod
->mIsConstant
;
1657 if ( isConst
!= method
.HasFlag(MethodInfo::Const
) ) {
1658 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1662 isConst
? "not " : "");
1665 // check that the params match
1666 const MMemberListT
& params
= ctxMethod
->GetMembers();
1668 if ( params
.size() != method
.GetParamCount() ) {
1669 wxLogError("Incorrect number of parameters for '%s::%s' "
1670 "in the docs: should be %d instead of %d.",
1673 params
.size(), method
.GetParamCount());
1677 for ( MemberIndex k
= params
.begin();
1682 // what else can a function have?
1683 wxASSERT( ctx
->GetContextType() == SP_CTX_PARAMETER
);
1685 spParameter
*ctxParam
= (spParameter
*)ctx
;
1686 const ParamInfo
& param
= method
.GetParam(nParam
);
1687 if ( m_checkParamNames
&&
1688 (param
.GetName() != ctxParam
->mName
) ) {
1691 wxLogError("Parameter #%d of '%s::%s' should be "
1692 "'%s' and not '%s'.",
1696 ctxParam
->mName
.c_str(),
1697 param
.GetName().c_str());
1702 if ( param
.GetType() != ctxParam
->mType
) {
1705 wxLogError("Type of parameter '%s' of '%s::%s' "
1706 "should be '%s' and not '%s'.",
1707 ctxParam
->mName
.c_str(),
1710 ctxParam
->mType
.c_str(),
1711 param
.GetType().GetName().c_str());
1716 if ( param
.GetDefValue() != ctxParam
->mInitVal
) {
1717 wxLogWarning("Default value of parameter '%s' of "
1718 "'%s::%s' should be '%s' and not "
1720 ctxParam
->mName
.c_str(),
1723 ctxParam
->mInitVal
.c_str(),
1724 param
.GetDefValue().c_str());
1730 // TODO OVER add real support for overloaded methods
1732 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1735 if ( aOverloadedMethods
.Index(nameMethod
) == wxNOT_FOUND
) {
1736 // mark all methods with this name as existing
1737 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1738 if ( methods
[nMethod
]->GetName() == nameMethod
)
1739 methodExists
[nMethod
] = TRUE
;
1742 aOverloadedMethods
.Add(nameMethod
);
1744 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1745 "stupid to find the right match - skipping "
1746 "the param and flags checks.",
1748 nameMethod
.c_str());
1750 //else: warning already given
1754 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1755 if ( !methodExists
[nMethod
] ) {
1756 const wxString
& nameMethod
= methods
[nMethod
]->GetName();
1757 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1760 wxLogError("'%s::%s' is documented but doesn't exist.",
1762 nameMethod
.c_str());
1767 delete [] methodExists
;
1770 // check that all classes we found in the docs really exist
1771 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1772 if ( !classExists
[nClass
] ) {
1775 wxLogError("Class '%s' is documented but doesn't exist.",
1776 m_classes
[nClass
].c_str());
1780 delete [] classExists
;
1785 DocManager::~DocManager()
1787 WX_CLEAR_ARRAY(m_methods
);
1790 // ---------------------------------------------------------------------------
1791 // IgnoreNamesHandler implementation
1792 // ---------------------------------------------------------------------------
1794 int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry
*first
,
1795 IgnoreListEntry
*second
)
1797 // first compare the classes
1798 int rc
= first
->m_classname
.Cmp(second
->m_classname
);
1800 rc
= first
->m_funcname
.Cmp(second
->m_funcname
);
1805 bool IgnoreNamesHandler::AddNamesFromFile(const wxString
& filename
)
1807 wxFile
file(filename
, wxFile::read
);
1808 if ( !file
.IsOpened() )
1811 off_t len
= file
.Length();
1812 if ( len
== wxInvalidOffset
)
1815 char *buf
= new char[len
+ 1];
1818 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1825 for ( const char *current
= buf
; ; current
++ ) {
1827 // skip DOS line separator
1828 if ( *current
== '\r' )
1832 if ( *current
== '\n' || *current
== '\0' ) {
1833 if ( line
[0u] != '#' ) {
1834 if ( line
.Find(':') != wxNOT_FOUND
) {
1835 wxString classname
= line
.BeforeFirst(':'),
1836 funcname
= line
.AfterLast(':');
1837 m_ignore
.Add(new IgnoreListEntry(classname
, funcname
));
1841 m_ignore
.Add(new IgnoreListEntry(line
, ""));
1846 if ( *current
== '\0' )
1861 // -----------------------------------------------------------------------------
1862 // global function implementation
1863 // -----------------------------------------------------------------------------
1865 static wxString
MakeLabel(const char *classname
, const char *funcname
)
1867 wxString
label(classname
);
1868 if ( funcname
&& funcname
[0] == '\\' ) {
1869 // we may have some special TeX macro - so far only \destruct exists,
1870 // but may be later others will be added
1871 static const char *macros
[] = { "destruct" };
1872 static const char *replacement
[] = { "dtor" };
1875 for ( n
= 0; n
< WXSIZEOF(macros
); n
++ ) {
1876 if ( strncmp(funcname
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) {
1882 if ( n
== WXSIZEOF(macros
) ) {
1883 wxLogWarning("unknown function name '%s' - leaving as is.",
1887 funcname
= replacement
[n
];
1899 static wxString
MakeHelpref(const char *argument
)
1902 helpref
<< "\\helpref{" << argument
<< "}{" << MakeLabel(argument
) << '}';
1907 static void TeXFilter(wxString
* str
)
1909 // TeX special which can be quoted (don't include backslash nor braces as
1911 static wxRegEx
reNonSpecialSpecials("[#$%&_]"),
1915 reNonSpecialSpecials
.ReplaceAll(str
, "\\\\\\0");
1917 // can't quote these ones as they produce accents when preceded by
1918 // backslash, so put them inside verb
1919 reAccents
.ReplaceAll(str
, "\\\\verb|\\0|");
1922 static void TeXUnfilter(wxString
* str
)
1924 // FIXME may be done much more quickly
1929 static wxRegEx
reNonSpecialSpecials("\\\\([#$%&_{}])"),
1930 reAccents("\\\\verb|([~^])|");
1932 reNonSpecialSpecials
.ReplaceAll(str
, "\\1");
1933 reAccents
.ReplaceAll(str
, "\\1");
1936 static wxString
GetAllComments(const spContext
& ctx
)
1939 const MCommentListT
& commentsList
= ctx
.GetCommentList();
1940 for ( MCommentListT::const_iterator i
= commentsList
.begin();
1941 i
!= commentsList
.end();
1943 wxString comment
= (*i
)->GetText();
1945 // don't take comments like "// ----------" &c
1946 comment
.Trim(FALSE
);
1948 comment
== wxString(comment
[0u], comment
.length() - 1) + '\n' )
1951 comments
<< comment
;
1957 static const char *GetCurrentTime(const char *timeFormat
)
1959 static char s_timeBuffer
[128];
1964 ptmNow
= localtime(&timeNow
);
1966 strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
);
1968 return s_timeBuffer
;
1971 static const wxString
GetVersionString()
1973 wxString version
= "$Revision$";
1974 wxRegEx("^\\$Revision$$").ReplaceFirst(&version
, "\\1");
1980 Revision 1.14 2001/07/19 13:51:29 VZ
1981 fixes to version string
1983 Revision 1.13 2001/07/19 13:44:57 VZ
1984 1. compilation fixes
1985 2. don't quote special characters inside verbatim environment
1987 Revision 1.12 2000/10/09 13:53:33 juliansmart
1989 Doc corrections; added HelpGen project files
1991 Revision 1.11 2000/07/15 19:50:42 cvsuser
1994 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
1995 don't trasnform output dir name to lower case
1997 Revision 1.10 2000/03/11 10:05:23 VS
1998 now compiles with wxBase
2000 Revision 1.9 2000/01/16 13:25:21 VS
2001 compilation fixes (gcc)
2003 Revision 1.8 1999/09/13 14:29:39 JS
2005 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2006 into src for simplicity; added VC++ 5 project file
2008 Revision 1.7 1999/02/21 22:32:32 VZ
2009 1. more C++ parser fixes - now it almost parses wx/string.h
2010 a) #if/#ifdef/#else (very) limited support
2011 b) param type fix - now indirection chars are correctly handled
2012 c) class/struct/union distinction
2013 d) public/private fixes
2014 e) Dump() function added - very useful for debugging
2016 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2017 by default, and this option switches it on)
2019 Revision 1.6 1999/02/20 23:00:26 VZ
2020 1. new 'diff' mode which seems to work
2021 2. output files are not overwritten in 'dmup' mode
2022 3. fixes for better handling of const functions and operators
2023 ----------------------------
2025 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2026 1. Parser improvements
2027 a) const and virtual methods are parsed correctly (not static yet)
2028 b) "const" which is part of the return type is not swallowed
2030 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2031 "//---------" kind comments discarded now.
2032 ----------------------------
2034 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2036 some tweaks to HelpGen
2037 ----------------------------
2039 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2041 HelpGen starting to compile with VC++
2042 ----------------------------
2044 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2046 supports typedefs, generates "See also:" and adds "virtual " for virtual
2048 ----------------------------
2050 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2052 HelpGen is a prototype of the tool for automatic generation of the .tex files
2053 for wxWindows documentation from C++ headers
2056 /* vi: set tw=80 et ts=4 sw=4: */