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 // add a function which sanitazes the string before writing it to the file
126 class wxTeXFile
: public wxFile
131 // write a string to file verbatim (should only be used for the strings
132 // inside verbatim environment)
133 bool WriteVerbatim(const wxString
& s
)
135 return wxFile::Write(s
);
138 // write a string quoting TeX specials in it
139 bool WriteTeX(const wxString
& s
)
144 return wxFile::Write(t
);
148 wxTeXFile(const wxTeXFile
&);
149 wxTeXFile
& operator=(const wxTeXFile
&);
152 // helper class which manages the classes and function names to ignore for
153 // the documentation purposes (used by both HelpGenVisitor and DocManager)
154 class IgnoreNamesHandler
157 IgnoreNamesHandler() : m_ignore(CompareIgnoreListEntries
) { }
158 ~IgnoreNamesHandler() { WX_CLEAR_ARRAY(m_ignore
); }
160 // load file with classes/functions to ignore (add them to the names we
162 bool AddNamesFromFile(const wxString
& filename
);
164 // return TRUE if we ignore this function
165 bool IgnoreMethod(const wxString
& classname
,
166 const wxString
& funcname
) const
168 if ( IgnoreClass(classname
) )
171 IgnoreListEntry
ignore(classname
, funcname
);
173 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
176 // return TRUE if we ignore this class entirely
177 bool IgnoreClass(const wxString
& classname
) const
179 IgnoreListEntry
ignore(classname
, "");
181 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
185 struct IgnoreListEntry
187 IgnoreListEntry(const wxString
& classname
,
188 const wxString
& funcname
)
189 : m_classname(classname
), m_funcname(funcname
)
193 wxString m_classname
;
194 wxString m_funcname
; // if empty, ignore class entirely
197 static int CompareIgnoreListEntries(IgnoreListEntry
*first
,
198 IgnoreListEntry
*second
);
200 // for efficiency, let's sort it
201 WX_DEFINE_SORTED_ARRAY(IgnoreListEntry
*, ArrayNamesToIgnore
);
203 ArrayNamesToIgnore m_ignore
;
206 IgnoreNamesHandler(const IgnoreNamesHandler
&);
207 IgnoreNamesHandler
& operator=(const IgnoreNamesHandler
&);
210 // visitor implementation which writes all collected data to a .tex file
211 class HelpGenVisitor
: public spVisitor
215 HelpGenVisitor(const wxString
& directoryOut
, bool overwrite
);
217 virtual void VisitFile( spFile
& fl
);
218 virtual void VisitClass( spClass
& cl
);
219 virtual void VisitEnumeration( spEnumeration
& en
);
220 virtual void VisitTypeDef( spTypeDef
& td
);
221 virtual void VisitPreprocessorLine( spPreprocessorLine
& pd
);
222 virtual void VisitAttribute( spAttribute
& attr
);
223 virtual void VisitOperation( spOperation
& op
);
224 virtual void VisitParameter( spParameter
& param
);
228 // get our `ignore' object
229 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
231 // shut up g++ warning (ain't it stupid?)
232 virtual ~HelpGenVisitor() { }
235 // (re)initialize the state
238 // insert documentation for enums/typedefs coming immediately before the
239 // class declaration into the class documentation
240 void InsertTypedefDocs();
241 void InsertEnumDocs();
243 // write the headers for corresponding sections (only once)
244 void InsertDataStructuresHeader();
245 void InsertMethodsHeader();
247 // terminate the function documentation if it was started
248 void CloseFunction();
250 wxString m_directoryOut
, // directory for the output
251 m_fileHeader
; // name of the .h file we parse
252 bool m_overwrite
; // overwrite existing files?
253 wxTeXFile m_file
; // file we're writing to now
256 bool m_inClass
, // TRUE after file successfully opened
257 m_inTypesSection
, // enums & typedefs go there
258 m_inMethodSection
, // functions go here
259 m_isFirstParam
, // first parameter of current function?
260 m_inFunction
; // we're parsing a function declaration
262 // holders for "saved" documentation
263 wxString m_textStoredTypedefs
,
264 m_textStoredFunctionComment
;
266 // for enums we have to use an array as we can't intermix the normal text
267 // and the text inside verbatim environment
268 wxArrayString m_storedEnums
,
271 // headers included by this file
272 wxArrayString m_headers
;
274 // ignore handler: tells us which classes to ignore for doc generation
276 IgnoreNamesHandler m_ignoreNames
;
279 HelpGenVisitor(const HelpGenVisitor
&);
280 HelpGenVisitor
& operator=(const HelpGenVisitor
&);
283 // documentation manager - a class which parses TeX files and remembers the
284 // functions documented in them and can later compare them with all functions
285 // found under ctxTop by C++ parser
289 DocManager(bool checkParamNames
);
292 // returns FALSE on failure
293 bool ParseTeXFile(const wxString
& filename
);
295 // returns FALSE if there were any differences
296 bool DumpDifferences(spContext
*ctxTop
) const;
298 // get our `ignore' object
299 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
305 // returns the length of 'match' if the string 'str' starts with it or 0
307 static size_t TryMatch(const char *str
, const char *match
);
309 // skip spaces: returns pointer to first non space character (also
310 // updates the value of m_line)
311 const char *SkipSpaces(const char *p
)
313 while ( isspace(*p
) ) {
321 // skips characters until the next 'c' in '*pp' unless it ends before in
322 // which case FALSE is returned and pp points to '\0', otherwise TRUE is
323 // returned and pp points to 'c'
324 bool SkipUntil(const char **pp
, char c
);
326 // the same as SkipUntil() but only spaces are skipped: on first non space
327 // character different from 'c' the function stops and returns FALSE
328 bool SkipSpaceUntil(const char **pp
, char c
);
330 // extract the string between {} and modify '*pp' to point at the
331 // character immediately after the closing '}'. The returned string is empty
333 wxString
ExtractStringBetweenBraces(const char **pp
);
335 // the current file and line while we're in ParseTeXFile (for error
340 // functions and classes to ignore during diff
341 // -------------------------------------------
343 IgnoreNamesHandler m_ignoreNames
;
345 // information about all functions documented in the TeX file(s)
346 // -------------------------------------------------------------
348 // info about a type: for now stored as text string, but must be parsed
349 // further later (to know that "char *" == "char []" - TODO)
353 TypeInfo(const wxString
& type
) : m_type(type
) { }
355 bool operator==(const wxString
& type
) const { return m_type
== type
; }
356 bool operator!=(const wxString
& type
) const { return m_type
!= type
; }
358 const wxString
& GetName() const { return m_type
; }
364 // info abotu a function parameter
368 ParamInfo(const wxString
& type
,
369 const wxString
& name
,
370 const wxString
& value
)
371 : m_type(type
), m_name(name
), m_value(value
)
375 const TypeInfo
& GetType() const { return m_type
; }
376 const wxString
& GetName() const { return m_name
; }
377 const wxString
& GetDefValue() const { return m_value
; }
380 TypeInfo m_type
; // type of parameter
381 wxString m_name
; // name
382 wxString m_value
; // default value
385 WX_DEFINE_ARRAY(ParamInfo
*, ArrayParamInfo
);
387 // info about a function
400 MethodInfo(const wxString
& type
,
401 const wxString
& name
,
402 const ArrayParamInfo
& params
)
403 : m_typeRet(type
), m_name(name
), m_params(params
)
408 void SetFlag(MethodFlags flag
) { m_flags
|= flag
; }
410 const TypeInfo
& GetType() const { return m_typeRet
; }
411 const wxString
& GetName() const { return m_name
; }
412 const ParamInfo
& GetParam(size_t n
) const { return *(m_params
[n
]); }
413 size_t GetParamCount() const { return m_params
.GetCount(); }
415 bool HasFlag(MethodFlags flag
) const { return (m_flags
& flag
) != 0; }
417 ~MethodInfo() { WX_CLEAR_ARRAY(m_params
); }
420 TypeInfo m_typeRet
; // return type
422 int m_flags
; // bit mask of the value from the enum above
424 ArrayParamInfo m_params
;
427 WX_DEFINE_ARRAY(MethodInfo
*, ArrayMethodInfo
);
428 WX_DEFINE_ARRAY(ArrayMethodInfo
*, ArrayMethodInfos
);
430 // first array contains the names of all classes we found, the second has a
431 // pointer to the array of methods of the given class at the same index as
432 // the class name appears in m_classes
433 wxArrayString m_classes
;
434 ArrayMethodInfos m_methods
;
436 // are we checking parameter names?
437 bool m_checkParamNames
;
440 DocManager(const DocManager
&);
441 DocManager
& operator=(const DocManager
&);
444 // -----------------------------------------------------------------------------
446 // -----------------------------------------------------------------------------
448 // =============================================================================
450 // =============================================================================
452 // this function never returns
455 wxString prog
= wxTheApp
->argv
[0];
456 wxString basename
= prog
.AfterLast('/');
459 basename
= prog
.AfterLast('\\');
465 "usage: %s [global options] <mode> [mode options] <files...>\n"
467 " where global options are:\n"
470 " -H give this usage message\n"
471 " -V print the version info\n"
472 " -i file file with classes/function to ignore\n"
474 " where mode is one of: dump, diff\n"
476 " dump means generate .tex files for TeX2RTF converter from specified\n"
477 " headers files, mode options are:\n"
478 " -f overwrite existing files\n"
479 " -o outdir directory for generated files\n"
481 " diff means compare the set of methods documented .tex file with the\n"
482 " methods declared in the header:\n"
483 " %s diff <file.h> <files.tex...>.\n"
484 " mode specific options are:\n"
485 " -p do check parameter names (not done by default)\n"
486 "\n", basename
.c_str(), basename
.c_str());
491 int HelpGenApp::OnRun()
504 wxArrayString filesH
, filesTeX
;
505 wxString directoryOut
, // directory for 'dmup' output
506 ignoreFile
; // file with classes/functions to ignore
507 bool overwrite
= FALSE
, // overwrite existing files during 'dump'?
508 paramNames
= FALSE
; // check param names during 'diff'?
510 for ( int current
= 1; current
< argc
; current
++ ) {
511 // all options have one letter
512 if ( argv
[current
][0] == '-' ) {
513 if ( argv
[current
][2] == '\0' ) {
514 switch ( argv
[current
][1] ) {
517 wxLog::GetActiveTarget()->SetVerbose();
522 wxLog::GetActiveTarget()->SetVerbose(FALSE
);
532 wxLogMessage("HelpGen version %s\n"
533 "(c) 1999-2001 Vadim Zeitlin\n",
534 GetVersionString().c_str());
539 if ( current
>= argc
) {
540 wxLogError("-i option requires an argument.");
545 ignoreFile
= argv
[current
];
549 if ( mode
!= Mode_Diff
) {
550 wxLogError("-p is only valid with diff.");
559 if ( mode
!= Mode_Dump
) {
560 wxLogError("-f is only valid with dump.");
569 if ( mode
!= Mode_Dump
) {
570 wxLogError("-o is only valid with dump.");
576 if ( current
>= argc
) {
577 wxLogError("-o option requires an argument.");
582 directoryOut
= argv
[current
];
583 if ( !!directoryOut
) {
584 // terminate with a '/' if it doesn't have it
585 switch ( directoryOut
.Last() ) {
596 //else: it's empty, do nothing
601 wxLogError("unknown option '%s'", argv
[current
]);
606 wxLogError("only one letter options are allowed, not '%s'.",
610 // only get here after a break from switch or from else branch of if
615 if ( mode
== Mode_None
) {
616 if ( strcmp(argv
[current
], "diff") == 0 )
618 else if ( strcmp(argv
[current
], "dump") == 0 )
621 wxLogError("unknown mode '%s'.", argv
[current
]);
627 if ( mode
== Mode_Dump
|| filesH
.IsEmpty() ) {
628 filesH
.Add(argv
[current
]);
631 // 2nd files and further are TeX files in diff mode
632 wxASSERT( mode
== Mode_Diff
);
634 filesTeX
.Add(argv
[current
]);
640 // create a parser object and a visitor derivation
641 CJSourceParser parser
;
642 HelpGenVisitor
visitor(directoryOut
, overwrite
);
643 if ( !!ignoreFile
&& mode
== Mode_Dump
)
644 visitor
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
646 spContext
*ctxTop
= NULL
;
648 // parse all header files
649 size_t nFiles
= filesH
.GetCount();
650 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
651 wxString header
= filesH
[n
];
652 ctxTop
= parser
.ParseFile(header
);
654 wxLogWarning("Header file '%s' couldn't be processed.",
657 else if ( mode
== Mode_Dump
) {
658 ((spFile
*)ctxTop
)->mFileName
= header
;
659 visitor
.VisitAll(*ctxTop
);
666 #endif // __WXDEBUG__
669 // parse all TeX files
670 if ( mode
== Mode_Diff
) {
672 wxLogError("Can't complete diff.");
678 DocManager
docman(paramNames
);
680 size_t nFiles
= filesTeX
.GetCount();
681 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
682 wxString file
= filesTeX
[n
];
683 if ( !docman
.ParseTeXFile(file
) ) {
684 wxLogWarning("TeX file '%s' couldn't be processed.",
690 docman
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
692 docman
.DumpDifferences(ctxTop
);
698 // -----------------------------------------------------------------------------
699 // HelpGenVisitor implementation
700 // -----------------------------------------------------------------------------
702 HelpGenVisitor::HelpGenVisitor(const wxString
& directoryOut
,
704 : m_directoryOut(directoryOut
)
706 m_overwrite
= overwrite
;
711 void HelpGenVisitor::Reset()
716 m_inMethodSection
= FALSE
;
718 m_textStoredTypedefs
=
719 m_textStoredFunctionComment
= "";
721 m_storedEnums
.Empty();
722 m_storedEnumsVerb
.Empty();
726 void HelpGenVisitor::InsertTypedefDocs()
728 m_file
.WriteTeX(m_textStoredTypedefs
);
729 m_textStoredTypedefs
.Empty();
732 void HelpGenVisitor::InsertEnumDocs()
734 size_t count
= m_storedEnums
.GetCount();
735 for ( size_t n
= 0; n
< count
; n
++ )
737 m_file
.WriteTeX(m_storedEnums
[n
]);
738 m_file
.WriteVerbatim(m_storedEnumsVerb
[n
] + '\n');
741 m_storedEnums
.Empty();
742 m_storedEnumsVerb
.Empty();
745 void HelpGenVisitor::InsertDataStructuresHeader()
747 if ( !m_inTypesSection
) {
748 m_inTypesSection
= TRUE
;
750 m_file
.Write("\\wxheading{Data structures}\n\n");
754 void HelpGenVisitor::InsertMethodsHeader()
756 if ( !m_inMethodSection
) {
757 m_inMethodSection
= TRUE
;
759 m_file
.Write( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
763 void HelpGenVisitor::CloseFunction()
765 if ( m_inFunction
) {
766 m_inFunction
= FALSE
;
769 if ( m_isFirstParam
) {
771 totalText
<< "\\void";
774 totalText
<< "}\n\n";
775 m_file
.Write(totalText
);
777 if ( !m_textStoredFunctionComment
.IsEmpty() )
778 m_file
.WriteTeX(m_textStoredFunctionComment
+ '\n');
782 void HelpGenVisitor::EndVisit()
786 m_fileHeader
.Empty();
788 wxLogVerbose("%s: finished generating for the current file.",
789 GetCurrentTime("%H:%M:%S"));
792 void HelpGenVisitor::VisitFile( spFile
& file
)
794 m_fileHeader
= file
.mFileName
;
795 wxLogVerbose("%s: started generating docs for classes from file '%s'...",
796 GetCurrentTime("%H:%M:%S"), m_fileHeader
.c_str());
799 void HelpGenVisitor::VisitClass( spClass
& cl
)
801 m_inClass
= FALSE
; // will be left FALSE on error
803 wxString name
= cl
.GetName();
805 if ( m_ignoreNames
.IgnoreClass(name
) ) {
806 wxLogVerbose("Skipping ignored class '%s'.", name
.c_str());
811 // the file name is built from the class name by removing the leading "wx"
812 // if any and converting it to the lower case
814 if ( name(0, 2) == "wx" ) {
815 filename
<< name
.c_str() + 2;
821 filename
.MakeLower();
823 filename
.Prepend(m_directoryOut
);
825 if ( !m_overwrite
&& wxFile::Exists(filename
) ) {
826 wxLogError("Won't overwrite existing file '%s' - please use '-f'.",
832 m_inClass
= m_file
.Open(filename
, wxFile::write
);
834 wxLogError("Can't generate documentation for the class '%s'.",
841 m_inTypesSection
= FALSE
;
843 wxLogInfo("Created new file '%s' for class '%s'.",
844 filename
.c_str(), name
.c_str());
846 // write out the header
849 "%% automatically generated by HelpGen %s from\n"
854 "\\section{\\class{%s}}\\label{%s}\n\n",
855 GetVersionString().c_str(),
856 m_fileHeader
.c_str(),
857 GetCurrentTime("%d/%b/%y %H:%M:%S"),
859 wxString(name
).MakeLower().c_str());
861 m_file
.Write(header
);
863 // the entire text we're writing to file
866 // if the header includes other headers they must be related to it... try to
867 // automatically generate the "See also" clause
868 if ( !m_headers
.IsEmpty() ) {
869 // correspondence between wxWindows headers and class names
870 static const char *headers
[] = {
879 // NULL here means not to insert anything in "See also" for the
880 // corresponding header
881 static const char *classes
[] = {
890 wxASSERT_MSG( WXSIZEOF(headers
) == WXSIZEOF(classes
),
891 "arrays must be in sync!" );
893 wxArrayInt interestingClasses
;
895 size_t count
= m_headers
.Count(), index
;
896 for ( size_t n
= 0; n
< count
; n
++ ) {
897 wxString baseHeaderName
= m_headers
[n
].Before('.');
898 if ( baseHeaderName(0, 3) != "wx/" )
901 baseHeaderName
.erase(0, 3);
902 for ( index
= 0; index
< WXSIZEOF(headers
); index
++ ) {
903 if ( Stricmp(baseHeaderName
, headers
[index
]) == 0 )
907 if ( (index
< WXSIZEOF(headers
)) && classes
[index
] ) {
908 // interesting header
909 interestingClasses
.Add(index
);
913 if ( !interestingClasses
.IsEmpty() ) {
914 // do generate "See also" clause
915 totalText
<< "\\wxheading{See also:}\n\n";
917 count
= interestingClasses
.Count();
918 for ( index
= 0; index
< count
; index
++ ) {
922 totalText
<< MakeHelpref(classes
[interestingClasses
[index
]]);
929 // the comment before the class generally explains what is it for so put it
930 // in place of the class description
931 if ( cl
.HasComments() ) {
932 wxString comment
= GetAllComments(cl
);
934 totalText
<< '\n' << comment
<< '\n';
937 // derived from section
938 wxString derived
= "\\wxheading{Derived from}\n\n";
940 const StrListT
& baseClasses
= cl
.mSuperClassNames
;
941 if ( baseClasses
.size() == 0 ) {
942 derived
<< "No base class";
946 for ( StrListT::const_iterator i
= baseClasses
.begin();
947 i
!= baseClasses
.end();
950 // separate from the previous one
957 wxString baseclass
= *i
;
958 derived
<< "\\helpref{" << baseclass
<< "}";
959 derived
<< "{" << baseclass
.MakeLower() << "}";
962 totalText
<< derived
<< "\n\n";
964 // write all this to file
965 m_file
.WriteTeX(totalText
);
967 // if there were any enums/typedefs before, insert their documentation now
968 InsertDataStructuresHeader();
973 void HelpGenVisitor::VisitEnumeration( spEnumeration
& en
)
977 if ( m_inMethodSection
) {
978 // FIXME that's a bug, but tell the user aboit it nevertheless... we
979 // should be smart enough to process even the enums which come after the
981 wxLogWarning("enum '%s' ignored, please put it before the class "
982 "methods.", en
.GetName().c_str());
986 // simply copy the enum text in the docs
987 wxString enumeration
= GetAllComments(en
),
990 enumerationVerb
<< "\\begin{verbatim}\n"
992 << "\n\\end{verbatim}\n";
994 // remember for later use if we're not inside a class yet
996 m_storedEnums
.Add(enumeration
);
997 m_storedEnumsVerb
.Add(enumerationVerb
);
1000 // write the header for this section if not done yet
1001 InsertDataStructuresHeader();
1003 m_file
.WriteTeX(enumeration
);
1004 m_file
.WriteVerbatim(enumerationVerb
);
1009 void HelpGenVisitor::VisitTypeDef( spTypeDef
& td
)
1013 if ( m_inMethodSection
) {
1014 // FIXME that's a bug, but tell the user aboit it nevertheless...
1015 wxLogWarning("typedef '%s' ignored, please put it before the class "
1016 "methods.", td
.GetName().c_str());
1020 wxString typedefdoc
;
1021 typedefdoc
<< "{\\small \\begin{verbatim}\n"
1022 << "typedef " << td
.mOriginalType
<< ' ' << td
.GetName()
1023 << "\n\\end{verbatim}}\n"
1024 << GetAllComments(td
);
1026 // remember for later use if we're not inside a class yet
1028 if ( !m_textStoredTypedefs
.IsEmpty() ) {
1029 m_textStoredTypedefs
<< '\n';
1032 m_textStoredTypedefs
<< typedefdoc
;
1035 // write the header for this section if not done yet
1036 InsertDataStructuresHeader();
1039 m_file
.WriteTeX(typedefdoc
);
1043 void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine
& pd
)
1045 switch ( pd
.GetStatementType() ) {
1046 case SP_PREP_DEF_INCLUDE_FILE
:
1047 m_headers
.Add(pd
.CPP_GetIncludedFileNeme());
1050 case SP_PREP_DEF_DEFINE_SYMBOL
:
1051 // TODO decide if it's a constant and document it if it is
1056 void HelpGenVisitor::VisitAttribute( spAttribute
& attr
)
1060 // only document the public member variables
1061 if ( !m_inClass
|| !attr
.IsPublic() )
1064 wxLogWarning("Ignoring member variable '%s'.", attr
.GetName().c_str());
1067 void HelpGenVisitor::VisitOperation( spOperation
& op
)
1072 // we don't generate docs right now - either we ignore this class
1073 // entirely or we couldn't open the file
1077 if ( !op
.IsInClass() ) {
1078 // TODO document global functions
1079 wxLogWarning("skipped global function '%s'.", op
.GetName().c_str());
1084 if ( op
.mVisibility
== SP_VIS_PRIVATE
) {
1085 // FIXME should we document protected functions?
1089 wxString funcname
= op
.GetName(),
1090 classname
= op
.GetClass().GetName();
1091 if ( m_ignoreNames
.IgnoreMethod(classname
, funcname
) ) {
1092 wxLogVerbose("Skipping ignored '%s::%s'.",
1093 classname
.c_str(), funcname
.c_str());
1098 InsertMethodsHeader();
1102 m_isFirstParam
= TRUE
;
1104 m_textStoredFunctionComment
= GetAllComments(op
);
1106 // start function documentation
1109 // check for the special case of dtor
1111 if ( (funcname
[0] == '~') && (classname
== funcname
.c_str() + 1) ) {
1112 dtor
.Printf("\\destruct{%s}", classname
.c_str());
1116 totalText
.Printf("\n"
1117 "\\membersection{%s::%s}\\label{%s}\n"
1119 "\\%sfunc{%s%s}{%s}{",
1120 classname
.c_str(), funcname
.c_str(),
1121 MakeLabel(classname
, funcname
).c_str(),
1122 op
.mIsConstant
? "const" : "",
1123 op
.mIsVirtual
? "virtual " : "",
1124 op
.mRetType
.c_str(),
1127 m_file
.WriteTeX(totalText
);
1130 void HelpGenVisitor::VisitParameter( spParameter
& param
)
1132 if ( !m_inFunction
)
1136 if ( m_isFirstParam
) {
1137 m_isFirstParam
= FALSE
;
1143 totalText
<< "\\param{" << param
.mType
<< " }{" << param
.GetName();
1144 wxString defvalue
= param
.mInitVal
;
1145 if ( !defvalue
.IsEmpty() ) {
1146 totalText
<< " = " << defvalue
;
1151 m_file
.WriteTeX(totalText
);
1154 // ---------------------------------------------------------------------------
1156 // ---------------------------------------------------------------------------
1158 DocManager::DocManager(bool checkParamNames
)
1160 m_checkParamNames
= checkParamNames
;
1163 size_t DocManager::TryMatch(const char *str
, const char *match
)
1165 size_t lenMatch
= 0;
1166 while ( str
[lenMatch
] == match
[lenMatch
] ) {
1169 if ( match
[lenMatch
] == '\0' )
1176 bool DocManager::SkipUntil(const char **pp
, char c
)
1178 const char *p
= *pp
;
1194 bool DocManager::SkipSpaceUntil(const char **pp
, char c
)
1196 const char *p
= *pp
;
1198 if ( !isspace(*p
) || *p
== '\0' )
1212 wxString
DocManager::ExtractStringBetweenBraces(const char **pp
)
1216 if ( !SkipSpaceUntil(pp
, '{') ) {
1217 wxLogWarning("file %s(%d): '{' expected after '\\param'",
1218 m_filename
.c_str(), m_line
);
1222 const char *startParam
= ++*pp
; // skip '{'
1224 if ( !SkipUntil(pp
, '}') ) {
1225 wxLogWarning("file %s(%d): '}' expected after '\\param'",
1226 m_filename
.c_str(), m_line
);
1229 result
= wxString(startParam
, (*pp
)++ - startParam
);
1236 bool DocManager::ParseTeXFile(const wxString
& filename
)
1238 m_filename
= filename
;
1240 wxFile
file(m_filename
, wxFile::read
);
1241 if ( !file
.IsOpened() )
1244 off_t len
= file
.Length();
1245 if ( len
== wxInvalidOffset
)
1248 char *buf
= new char[len
+ 1];
1251 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1257 // reinit everything
1260 wxLogVerbose("%s: starting to parse doc file '%s'.",
1261 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1263 // the name of the class from the last "\membersection" command: we assume
1264 // that the following "\func" or "\constfunc" always documents a method of
1265 // this class (and it should always be like that in wxWindows documentation)
1268 for ( const char *current
= buf
; current
- buf
< len
; current
++ ) {
1269 // FIXME parsing is awfully inefficient
1271 if ( *current
== '%' ) {
1272 // comment, skip until the end of line
1274 SkipUntil(¤t
, '\n');
1279 // all the command we're interested in start with '\\'
1280 while ( *current
!= '\\' && *current
!= '\0' ) {
1281 if ( *current
++ == '\n' )
1285 if ( *current
== '\0' ) {
1286 // no more TeX commands left
1290 current
++; // skip '\\'
1298 } foundCommand
= Nothing
;
1300 size_t lenMatch
= TryMatch(current
, "func");
1302 foundCommand
= Func
;
1305 lenMatch
= TryMatch(current
, "constfunc");
1307 foundCommand
= ConstFunc
;
1309 lenMatch
= TryMatch(current
, "membersection");
1312 foundCommand
= MemberSect
;
1316 if ( foundCommand
== Nothing
)
1319 current
+= lenMatch
;
1321 if ( !SkipSpaceUntil(¤t
, '{') ) {
1322 wxLogWarning("file %s(%d): '{' expected after \\func, "
1323 "\\constfunc or \\membersection.",
1324 m_filename
.c_str(), m_line
);
1331 if ( foundCommand
== MemberSect
) {
1332 // what follows has the form <classname>::<funcname>
1333 const char *startClass
= current
;
1334 if ( !SkipUntil(¤t
, ':') || *(current
+ 1) != ':' ) {
1335 wxLogWarning("file %s(%d): '::' expected after "
1336 "\\membersection.", m_filename
.c_str(), m_line
);
1339 classname
= wxString(startClass
, current
- startClass
);
1340 TeXUnfilter(&classname
);
1346 // extract the return type
1347 const char *startRetType
= current
;
1349 if ( !SkipUntil(¤t
, '}') ) {
1350 wxLogWarning("file %s(%d): '}' expected after return type",
1351 m_filename
.c_str(), m_line
);
1356 wxString returnType
= wxString(startRetType
, current
- startRetType
);
1357 TeXUnfilter(&returnType
);
1360 if ( !SkipSpaceUntil(¤t
, '{') ) {
1361 wxLogWarning("file %s(%d): '{' expected after return type",
1362 m_filename
.c_str(), m_line
);
1368 const char *funcEnd
= current
;
1369 if ( !SkipUntil(&funcEnd
, '}') ) {
1370 wxLogWarning("file %s(%d): '}' expected after function name",
1371 m_filename
.c_str(), m_line
);
1376 wxString funcName
= wxString(current
, funcEnd
- current
);
1377 current
= funcEnd
+ 1;
1379 // trim spaces from both sides
1380 funcName
.Trim(FALSE
);
1381 funcName
.Trim(TRUE
);
1383 // special cases: '$...$' may be used for LaTeX inline math, remove the
1385 if ( funcName
.Find('$') != wxNOT_FOUND
) {
1387 for ( const char *p
= funcName
.c_str(); *p
!= '\0'; p
++ ) {
1388 if ( *p
!= '$' && !isspace(*p
) )
1395 // \destruct{foo} is really ~foo
1396 if ( funcName
[0u] == '\\' ) {
1397 size_t len
= strlen("\\destruct{");
1398 if ( funcName(0, len
) != "\\destruct{" ) {
1399 wxLogWarning("file %s(%d): \\destruct expected",
1400 m_filename
.c_str(), m_line
);
1405 funcName
.erase(0, len
);
1406 funcName
.Prepend('~');
1408 if ( !SkipSpaceUntil(¤t
, '}') ) {
1409 wxLogWarning("file %s(%d): '}' expected after destructor",
1410 m_filename
.c_str(), m_line
);
1415 funcEnd
++; // there is an extra '}' to count
1418 TeXUnfilter(&funcName
);
1421 current
= funcEnd
+ 1; // skip '}'
1422 if ( !SkipSpaceUntil(¤t
, '{') ||
1423 (current
++, !SkipSpaceUntil(¤t
, '\\')) ) {
1424 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1425 m_filename
.c_str(), m_line
);
1430 wxArrayString paramNames
, paramTypes
, paramValues
;
1432 bool isVararg
= FALSE
;
1434 current
++; // skip '\\'
1435 lenMatch
= TryMatch(current
, "void");
1437 lenMatch
= TryMatch(current
, "param");
1438 while ( lenMatch
&& (current
- buf
< len
) ) {
1439 current
+= lenMatch
;
1441 // now come {paramtype}{paramname}
1442 wxString paramType
= ExtractStringBetweenBraces(¤t
);
1443 if ( !!paramType
) {
1444 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1445 if ( !!paramText
) {
1446 // the param declaration may contain default value
1447 wxString paramName
= paramText
.BeforeFirst('='),
1448 paramValue
= paramText
.AfterFirst('=');
1450 // sanitize all strings
1451 TeXUnfilter(¶mValue
);
1452 TeXUnfilter(¶mName
);
1453 TeXUnfilter(¶mType
);
1455 paramValues
.Add(paramValue
);
1456 paramNames
.Add(paramName
);
1457 paramTypes
.Add(paramType
);
1462 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1463 if ( paramText
== "..." ) {
1467 wxLogWarning("Parameters of '%s::%s' are in "
1469 classname
.c_str(), funcName
.c_str());
1474 current
= SkipSpaces(current
);
1475 if ( *current
== ',' || *current
== '}' ) {
1476 current
= SkipSpaces(++current
);
1478 lenMatch
= TryMatch(current
, "\\param");
1481 wxLogWarning("file %s(%d): ',' or '}' expected after "
1482 "'\\param'", m_filename
.c_str(), m_line
);
1488 // if we got here there was no '\\void', so must have some params
1489 if ( paramNames
.IsEmpty() ) {
1490 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1491 m_filename
.c_str(), m_line
);
1497 // verbose diagnostic output
1499 size_t param
, paramCount
= paramNames
.GetCount();
1500 for ( param
= 0; param
< paramCount
; param
++ ) {
1505 paramsAll
<< paramTypes
[param
] << ' ' << paramNames
[param
];
1508 wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
1509 m_filename
.c_str(), m_line
,
1514 foundCommand
== ConstFunc
? " const" : "");
1516 // store the info about the just found function
1517 ArrayMethodInfo
*methods
;
1518 int index
= m_classes
.Index(classname
);
1519 if ( index
== wxNOT_FOUND
) {
1520 m_classes
.Add(classname
);
1522 methods
= new ArrayMethodInfo
;
1523 m_methods
.Add(methods
);
1526 methods
= m_methods
[(size_t)index
];
1529 ArrayParamInfo params
;
1530 for ( param
= 0; param
< paramCount
; param
++ ) {
1531 params
.Add(new ParamInfo(paramTypes
[param
],
1533 paramValues
[param
]));
1536 MethodInfo
*method
= new MethodInfo(returnType
, funcName
, params
);
1537 if ( foundCommand
== ConstFunc
)
1538 method
->SetFlag(MethodInfo::Const
);
1540 method
->SetFlag(MethodInfo::Vararg
);
1542 methods
->Add(method
);
1547 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1548 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1553 bool DocManager::DumpDifferences(spContext
*ctxTop
) const
1555 typedef MMemberListT::const_iterator MemberIndex
;
1557 bool foundDiff
= FALSE
;
1559 // flag telling us whether the given class was found at all in the header
1560 size_t nClass
, countClassesInDocs
= m_classes
.GetCount();
1561 bool *classExists
= new bool[countClassesInDocs
];
1562 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1563 classExists
[nClass
] = FALSE
;
1566 // ctxTop is normally an spFile
1567 wxASSERT( ctxTop
->GetContextType() == SP_CTX_FILE
);
1569 const MMemberListT
& classes
= ctxTop
->GetMembers();
1570 for ( MemberIndex i
= classes
.begin(); i
!= classes
.end(); i
++ ) {
1571 spContext
*ctx
= *i
;
1572 if ( ctx
->GetContextType() != SP_CTX_CLASS
) {
1573 // TODO process also global functions, macros, ...
1577 spClass
*ctxClass
= (spClass
*)ctx
;
1578 const wxString
& nameClass
= ctxClass
->mName
;
1579 int index
= m_classes
.Index(nameClass
);
1580 if ( index
== wxNOT_FOUND
) {
1581 if ( !m_ignoreNames
.IgnoreClass(nameClass
) ) {
1584 wxLogError("Class '%s' is not documented at all.",
1588 // it makes no sense to check for its functions
1592 classExists
[index
] = TRUE
;
1595 // array of method descriptions for this class
1596 const ArrayMethodInfo
& methods
= *(m_methods
[index
]);
1597 size_t nMethod
, countMethods
= methods
.GetCount();
1599 // flags telling if we already processed given function
1600 bool *methodExists
= new bool[countMethods
];
1601 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1602 methodExists
[nMethod
] = FALSE
;
1605 wxArrayString aOverloadedMethods
;
1607 const MMemberListT
& functions
= ctxClass
->GetMembers();
1608 for ( MemberIndex j
= functions
.begin(); j
!= functions
.end(); j
++ ) {
1610 if ( ctx
->GetContextType() != SP_CTX_OPERATION
)
1613 spOperation
*ctxMethod
= (spOperation
*)ctx
;
1614 const wxString
& nameMethod
= ctxMethod
->mName
;
1616 // find all functions with the same name
1617 wxArrayInt aMethodsWithSameName
;
1618 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1619 if ( methods
[nMethod
]->GetName() == nameMethod
)
1620 aMethodsWithSameName
.Add(nMethod
);
1623 if ( aMethodsWithSameName
.IsEmpty() && ctxMethod
->IsPublic() ) {
1624 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1627 wxLogError("'%s::%s' is not documented.",
1629 nameMethod
.c_str());
1632 // don't check params
1635 else if ( aMethodsWithSameName
.GetCount() == 1 ) {
1636 index
= (size_t)aMethodsWithSameName
[0u];
1637 methodExists
[index
] = TRUE
;
1639 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1642 if ( !ctxMethod
->IsPublic() ) {
1643 wxLogWarning("'%s::%s' is documented but not public.",
1645 nameMethod
.c_str());
1648 // check that the flags match
1649 const MethodInfo
& method
= *(methods
[index
]);
1651 bool isVirtual
= ctxMethod
->mIsVirtual
;
1652 if ( isVirtual
!= method
.HasFlag(MethodInfo::Virtual
) ) {
1653 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1657 isVirtual
? "not " : "");
1660 bool isConst
= ctxMethod
->mIsConstant
;
1661 if ( isConst
!= method
.HasFlag(MethodInfo::Const
) ) {
1662 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1666 isConst
? "not " : "");
1669 // check that the params match
1670 const MMemberListT
& params
= ctxMethod
->GetMembers();
1672 if ( params
.size() != method
.GetParamCount() ) {
1673 wxLogError("Incorrect number of parameters for '%s::%s' "
1674 "in the docs: should be %d instead of %d.",
1677 params
.size(), method
.GetParamCount());
1681 for ( MemberIndex k
= params
.begin();
1686 // what else can a function have?
1687 wxASSERT( ctx
->GetContextType() == SP_CTX_PARAMETER
);
1689 spParameter
*ctxParam
= (spParameter
*)ctx
;
1690 const ParamInfo
& param
= method
.GetParam(nParam
);
1691 if ( m_checkParamNames
&&
1692 (param
.GetName() != ctxParam
->mName
) ) {
1695 wxLogError("Parameter #%d of '%s::%s' should be "
1696 "'%s' and not '%s'.",
1700 ctxParam
->mName
.c_str(),
1701 param
.GetName().c_str());
1706 if ( param
.GetType() != ctxParam
->mType
) {
1709 wxLogError("Type of parameter '%s' of '%s::%s' "
1710 "should be '%s' and not '%s'.",
1711 ctxParam
->mName
.c_str(),
1714 ctxParam
->mType
.c_str(),
1715 param
.GetType().GetName().c_str());
1720 if ( param
.GetDefValue() != ctxParam
->mInitVal
) {
1721 wxLogWarning("Default value of parameter '%s' of "
1722 "'%s::%s' should be '%s' and not "
1724 ctxParam
->mName
.c_str(),
1727 ctxParam
->mInitVal
.c_str(),
1728 param
.GetDefValue().c_str());
1734 // TODO OVER add real support for overloaded methods
1736 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1739 if ( aOverloadedMethods
.Index(nameMethod
) == wxNOT_FOUND
) {
1740 // mark all methods with this name as existing
1741 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1742 if ( methods
[nMethod
]->GetName() == nameMethod
)
1743 methodExists
[nMethod
] = TRUE
;
1746 aOverloadedMethods
.Add(nameMethod
);
1748 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1749 "stupid to find the right match - skipping "
1750 "the param and flags checks.",
1752 nameMethod
.c_str());
1754 //else: warning already given
1758 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1759 if ( !methodExists
[nMethod
] ) {
1760 const wxString
& nameMethod
= methods
[nMethod
]->GetName();
1761 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1764 wxLogError("'%s::%s' is documented but doesn't exist.",
1766 nameMethod
.c_str());
1771 delete [] methodExists
;
1774 // check that all classes we found in the docs really exist
1775 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1776 if ( !classExists
[nClass
] ) {
1779 wxLogError("Class '%s' is documented but doesn't exist.",
1780 m_classes
[nClass
].c_str());
1784 delete [] classExists
;
1789 DocManager::~DocManager()
1791 WX_CLEAR_ARRAY(m_methods
);
1794 // ---------------------------------------------------------------------------
1795 // IgnoreNamesHandler implementation
1796 // ---------------------------------------------------------------------------
1798 int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry
*first
,
1799 IgnoreListEntry
*second
)
1801 // first compare the classes
1802 int rc
= first
->m_classname
.Cmp(second
->m_classname
);
1804 rc
= first
->m_funcname
.Cmp(second
->m_funcname
);
1809 bool IgnoreNamesHandler::AddNamesFromFile(const wxString
& filename
)
1811 wxFile
file(filename
, wxFile::read
);
1812 if ( !file
.IsOpened() )
1815 off_t len
= file
.Length();
1816 if ( len
== wxInvalidOffset
)
1819 char *buf
= new char[len
+ 1];
1822 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1829 for ( const char *current
= buf
; ; current
++ ) {
1831 // skip DOS line separator
1832 if ( *current
== '\r' )
1836 if ( *current
== '\n' || *current
== '\0' ) {
1837 if ( line
[0u] != '#' ) {
1838 if ( line
.Find(':') != wxNOT_FOUND
) {
1839 wxString classname
= line
.BeforeFirst(':'),
1840 funcname
= line
.AfterLast(':');
1841 m_ignore
.Add(new IgnoreListEntry(classname
, funcname
));
1845 m_ignore
.Add(new IgnoreListEntry(line
, ""));
1850 if ( *current
== '\0' )
1865 // -----------------------------------------------------------------------------
1866 // global function implementation
1867 // -----------------------------------------------------------------------------
1869 static wxString
MakeLabel(const char *classname
, const char *funcname
)
1871 wxString
label(classname
);
1872 if ( funcname
&& funcname
[0] == '\\' ) {
1873 // we may have some special TeX macro - so far only \destruct exists,
1874 // but may be later others will be added
1875 static const char *macros
[] = { "destruct" };
1876 static const char *replacement
[] = { "dtor" };
1879 for ( n
= 0; n
< WXSIZEOF(macros
); n
++ ) {
1880 if ( strncmp(funcname
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) {
1886 if ( n
== WXSIZEOF(macros
) ) {
1887 wxLogWarning("unknown function name '%s' - leaving as is.",
1891 funcname
= replacement
[n
];
1903 static wxString
MakeHelpref(const char *argument
)
1906 helpref
<< "\\helpref{" << argument
<< "}{" << MakeLabel(argument
) << '}';
1911 static void TeXFilter(wxString
* str
)
1913 // TeX special which can be quoted (don't include backslash nor braces as
1915 static wxRegEx
reNonSpecialSpecials("[#$%&_]"),
1919 reNonSpecialSpecials
.ReplaceAll(str
, "\\\\\\0");
1921 // can't quote these ones as they produce accents when preceded by
1922 // backslash, so put them inside verb
1923 reAccents
.ReplaceAll(str
, "\\\\verb|\\0|");
1926 static void TeXUnfilter(wxString
* str
)
1928 // FIXME may be done much more quickly
1933 static wxRegEx
reNonSpecialSpecials("\\\\([#$%&_{}])"),
1934 reAccents("\\\\verb|([~^])|");
1936 reNonSpecialSpecials
.ReplaceAll(str
, "\\1");
1937 reAccents
.ReplaceAll(str
, "\\1");
1940 static wxString
GetAllComments(const spContext
& ctx
)
1943 const MCommentListT
& commentsList
= ctx
.GetCommentList();
1944 for ( MCommentListT::const_iterator i
= commentsList
.begin();
1945 i
!= commentsList
.end();
1947 wxString comment
= (*i
)->GetText();
1949 // don't take comments like "// ----------" &c
1950 comment
.Trim(FALSE
);
1952 comment
== wxString(comment
[0u], comment
.length() - 1) + '\n' )
1955 comments
<< comment
;
1961 static const char *GetCurrentTime(const char *timeFormat
)
1963 static char s_timeBuffer
[128];
1968 ptmNow
= localtime(&timeNow
);
1970 strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
);
1972 return s_timeBuffer
;
1975 static const wxString
GetVersionString()
1977 wxString version
= "$Revision$";
1978 wxRegEx("^\\$Revision$$").ReplaceFirst(&version
, "\\1");
1984 Revision 1.16 2001/11/28 19:27:33 VZ
1985 HelpGen doesn't work in GUI mode
1987 Revision 1.15 2001/11/22 21:59:58 GD
1988 use "..." instead of <...> for wx headers
1990 Revision 1.14 2001/07/19 13:51:29 VZ
1991 fixes to version string
1993 Revision 1.13 2001/07/19 13:44:57 VZ
1994 1. compilation fixes
1995 2. don't quote special characters inside verbatim environment
1997 Revision 1.12 2000/10/09 13:53:33 juliansmart
1999 Doc corrections; added HelpGen project files
2001 Revision 1.11 2000/07/15 19:50:42 cvsuser
2004 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
2005 don't trasnform output dir name to lower case
2007 Revision 1.10 2000/03/11 10:05:23 VS
2008 now compiles with wxBase
2010 Revision 1.9 2000/01/16 13:25:21 VS
2011 compilation fixes (gcc)
2013 Revision 1.8 1999/09/13 14:29:39 JS
2015 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2016 into src for simplicity; added VC++ 5 project file
2018 Revision 1.7 1999/02/21 22:32:32 VZ
2019 1. more C++ parser fixes - now it almost parses wx/string.h
2020 a) #if/#ifdef/#else (very) limited support
2021 b) param type fix - now indirection chars are correctly handled
2022 c) class/struct/union distinction
2023 d) public/private fixes
2024 e) Dump() function added - very useful for debugging
2026 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2027 by default, and this option switches it on)
2029 Revision 1.6 1999/02/20 23:00:26 VZ
2030 1. new 'diff' mode which seems to work
2031 2. output files are not overwritten in 'dmup' mode
2032 3. fixes for better handling of const functions and operators
2033 ----------------------------
2035 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2036 1. Parser improvements
2037 a) const and virtual methods are parsed correctly (not static yet)
2038 b) "const" which is part of the return type is not swallowed
2040 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2041 "//---------" kind comments discarded now.
2042 ----------------------------
2044 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2046 some tweaks to HelpGen
2047 ----------------------------
2049 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2051 HelpGen starting to compile with VC++
2052 ----------------------------
2054 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2056 supports typedefs, generates "See also:" and adds "virtual " for virtual
2058 ----------------------------
2060 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2062 HelpGen is a prototype of the tool for automatic generation of the .tex files
2063 for wxWindows documentation from C++ headers
2066 /* vi: set tw=80 et ts=4 sw=4: */