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"
69 // C++ parsing classes
76 // argh, Windows defines this
81 // -----------------------------------------------------------------------------
83 // -----------------------------------------------------------------------------
85 class HelpGenApp
: public wxApp
90 // don't let wxWin parse our cmd line, we do it ourselves
91 virtual bool OnInit() { return TRUE
; }
96 // IMPLEMENT_APP(HelpGenApp);
98 // -----------------------------------------------------------------------------
100 // -----------------------------------------------------------------------------
102 // return the label for the given function name (i.e. argument of \label)
103 static wxString
MakeLabel(const char *classname
, const char *funcname
= NULL
);
105 // return the whole \helpref{arg}{arg_label} string
106 static wxString
MakeHelpref(const char *argument
);
108 // [un]quote special TeX characters (in place)
109 static void TeXFilter(wxString
* str
);
110 static void TeXUnfilter(wxString
* str
); // also trims spaces
112 // get all comments associated with this context
113 static wxString
GetAllComments(const spContext
& ctx
);
115 // get the string with current time (returns pointer to static buffer)
116 // timeFormat is used for the call of strftime(3)
117 static const char *GetCurrentTime(const char *timeFormat
);
119 // get the string containing the program version
120 static const wxString
GetVersionString();
122 // -----------------------------------------------------------------------------
124 // -----------------------------------------------------------------------------
126 // a function documentation entry
127 struct FunctionDocEntry
129 FunctionDocEntry(const wxString
& name_
, const wxString
& text_
)
130 : name(name_
), text(text_
) { }
135 // the function doc text
139 static int Compare(FunctionDocEntry
**pp1
, FunctionDocEntry
**pp2
)
141 // the methods should appear in the following order: ctors, dtor, all
142 // the rest in the alphabetical order
143 bool isCtor1
= (*pp1
)->name
== classname
;
144 bool isCtor2
= (*pp2
)->name
== classname
;
148 // we don't order the ctors because we don't know how to do it
152 // ctor comes before non-ctor
157 // non-ctor must come after ctor
161 wxString dtorname
= wxString('~') + classname
;
163 // there is only one dtor, so the logic here is simpler
164 if ( (*pp1
)->name
== dtorname
) {
167 else if ( (*pp2
)->name
== dtorname
) {
171 // two normal methods
172 return strcmp((*pp1
)->name
, (*pp2
)->name
);
176 static wxString classname
;
179 wxString
FunctionDocEntry::classname
;
181 WX_DECLARE_OBJARRAY(FunctionDocEntry
, FunctionDocEntries
);
183 #include "wx/arrimpl.cpp"
185 WX_DEFINE_OBJARRAY(FunctionDocEntries
);
187 // add a function which sanitazes the string before writing it to the file and
188 // also capable of delaying output and sorting it before really writing it to
189 // the file (done from FlushAll())
190 class wxTeXFile
: public wxFile
195 // write a string to file verbatim (should only be used for the strings
196 // inside verbatim environment)
197 void WriteVerbatim(const wxString
& s
)
202 // write a string quoting TeX specials in it
203 void WriteTeX(const wxString
& s
)
211 // do write everything to file
214 if ( m_text
.empty() )
217 if ( !Write(m_text
) ) {
218 wxLogError("Failed to output generated documentation.");
229 wxTeXFile(const wxTeXFile
&);
230 wxTeXFile
& operator=(const wxTeXFile
&);
235 // helper class which manages the classes and function names to ignore for
236 // the documentation purposes (used by both HelpGenVisitor and DocManager)
237 class IgnoreNamesHandler
240 IgnoreNamesHandler() : m_ignore(CompareIgnoreListEntries
) { }
241 ~IgnoreNamesHandler() { WX_CLEAR_ARRAY(m_ignore
); }
243 // load file with classes/functions to ignore (add them to the names we
245 bool AddNamesFromFile(const wxString
& filename
);
247 // return TRUE if we ignore this function
248 bool IgnoreMethod(const wxString
& classname
,
249 const wxString
& funcname
) const
251 if ( IgnoreClass(classname
) )
254 IgnoreListEntry
ignore(classname
, funcname
);
256 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
259 // return TRUE if we ignore this class entirely
260 bool IgnoreClass(const wxString
& classname
) const
262 IgnoreListEntry
ignore(classname
, "");
264 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
268 struct IgnoreListEntry
270 IgnoreListEntry(const wxString
& classname
,
271 const wxString
& funcname
)
272 : m_classname(classname
), m_funcname(funcname
)
276 wxString m_classname
;
277 wxString m_funcname
; // if empty, ignore class entirely
280 static int CompareIgnoreListEntries(IgnoreListEntry
*first
,
281 IgnoreListEntry
*second
);
283 // for efficiency, let's sort it
284 WX_DEFINE_SORTED_ARRAY(IgnoreListEntry
*, ArrayNamesToIgnore
);
286 ArrayNamesToIgnore m_ignore
;
289 IgnoreNamesHandler(const IgnoreNamesHandler
&);
290 IgnoreNamesHandler
& operator=(const IgnoreNamesHandler
&);
293 // visitor implementation which writes all collected data to a .tex file
294 class HelpGenVisitor
: public spVisitor
298 HelpGenVisitor(const wxString
& directoryOut
, bool overwrite
);
300 virtual void VisitFile( spFile
& fl
);
301 virtual void VisitClass( spClass
& cl
);
302 virtual void VisitEnumeration( spEnumeration
& en
);
303 virtual void VisitTypeDef( spTypeDef
& td
);
304 virtual void VisitPreprocessorLine( spPreprocessorLine
& pd
);
305 virtual void VisitAttribute( spAttribute
& attr
);
306 virtual void VisitOperation( spOperation
& op
);
307 virtual void VisitParameter( spParameter
& param
);
311 // get our `ignore' object
312 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
314 // shut up g++ warning (ain't it stupid?)
315 virtual ~HelpGenVisitor() { }
318 // (re)initialize the state
321 // insert documentation for enums/typedefs coming immediately before the
322 // class declaration into the class documentation
323 void InsertTypedefDocs();
324 void InsertEnumDocs();
326 // write the headers for corresponding sections (only once)
327 void InsertDataStructuresHeader();
328 void InsertMethodsHeader();
330 // terminate the function documentation if it was started
331 void CloseFunction();
333 // write out all function docs when there are no more left in this class
334 // after sorting them in alphabetical order
337 wxString m_directoryOut
, // directory for the output
338 m_fileHeader
; // name of the .h file we parse
339 bool m_overwrite
; // overwrite existing files?
340 wxTeXFile m_file
; // file we're writing to now
343 bool m_inClass
, // TRUE after file successfully opened
344 m_inTypesSection
, // enums & typedefs go there
345 m_inMethodSection
, // functions go here
346 m_isFirstParam
; // first parameter of current function?
348 // non empty while parsing a class
349 wxString m_classname
;
351 // these are only non-empty while parsing a method:
352 wxString m_funcName
, // the function name
353 m_textFunc
; // the function doc text
355 // the array containing the documentation entries for the functions in the
356 // class currently being parsed
357 FunctionDocEntries m_arrayFuncDocs
;
359 // holders for "saved" documentation
360 wxString m_textStoredTypedefs
,
361 m_textStoredFunctionComment
;
363 // for enums we have to use an array as we can't intermix the normal text
364 // and the text inside verbatim environment
365 wxArrayString m_storedEnums
,
368 // headers included by this file
369 wxArrayString m_headers
;
371 // ignore handler: tells us which classes to ignore for doc generation
373 IgnoreNamesHandler m_ignoreNames
;
376 HelpGenVisitor(const HelpGenVisitor
&);
377 HelpGenVisitor
& operator=(const HelpGenVisitor
&);
380 // documentation manager - a class which parses TeX files and remembers the
381 // functions documented in them and can later compare them with all functions
382 // found under ctxTop by C++ parser
386 DocManager(bool checkParamNames
);
389 // returns FALSE on failure
390 bool ParseTeXFile(const wxString
& filename
);
392 // returns FALSE if there were any differences
393 bool DumpDifferences(spContext
*ctxTop
) const;
395 // get our `ignore' object
396 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
402 // returns the length of 'match' if the string 'str' starts with it or 0
404 static size_t TryMatch(const char *str
, const char *match
);
406 // skip spaces: returns pointer to first non space character (also
407 // updates the value of m_line)
408 const char *SkipSpaces(const char *p
)
410 while ( isspace(*p
) ) {
418 // skips characters until the next 'c' in '*pp' unless it ends before in
419 // which case FALSE is returned and pp points to '\0', otherwise TRUE is
420 // returned and pp points to 'c'
421 bool SkipUntil(const char **pp
, char c
);
423 // the same as SkipUntil() but only spaces are skipped: on first non space
424 // character different from 'c' the function stops and returns FALSE
425 bool SkipSpaceUntil(const char **pp
, char c
);
427 // extract the string between {} and modify '*pp' to point at the
428 // character immediately after the closing '}'. The returned string is empty
430 wxString
ExtractStringBetweenBraces(const char **pp
);
432 // the current file and line while we're in ParseTeXFile (for error
437 // functions and classes to ignore during diff
438 // -------------------------------------------
440 IgnoreNamesHandler m_ignoreNames
;
442 // information about all functions documented in the TeX file(s)
443 // -------------------------------------------------------------
445 // info about a type: for now stored as text string, but must be parsed
446 // further later (to know that "char *" == "char []" - TODO)
450 TypeInfo(const wxString
& type
) : m_type(type
) { }
452 bool operator==(const wxString
& type
) const { return m_type
== type
; }
453 bool operator!=(const wxString
& type
) const { return m_type
!= type
; }
455 const wxString
& GetName() const { return m_type
; }
461 // info abotu a function parameter
465 ParamInfo(const wxString
& type
,
466 const wxString
& name
,
467 const wxString
& value
)
468 : m_type(type
), m_name(name
), m_value(value
)
472 const TypeInfo
& GetType() const { return m_type
; }
473 const wxString
& GetName() const { return m_name
; }
474 const wxString
& GetDefValue() const { return m_value
; }
477 TypeInfo m_type
; // type of parameter
478 wxString m_name
; // name
479 wxString m_value
; // default value
482 WX_DEFINE_ARRAY(ParamInfo
*, ArrayParamInfo
);
484 // info about a function
497 MethodInfo(const wxString
& type
,
498 const wxString
& name
,
499 const ArrayParamInfo
& params
)
500 : m_typeRet(type
), m_name(name
), m_params(params
)
505 void SetFlag(MethodFlags flag
) { m_flags
|= flag
; }
507 const TypeInfo
& GetType() const { return m_typeRet
; }
508 const wxString
& GetName() const { return m_name
; }
509 const ParamInfo
& GetParam(size_t n
) const { return *(m_params
[n
]); }
510 size_t GetParamCount() const { return m_params
.GetCount(); }
512 bool HasFlag(MethodFlags flag
) const { return (m_flags
& flag
) != 0; }
514 ~MethodInfo() { WX_CLEAR_ARRAY(m_params
); }
517 TypeInfo m_typeRet
; // return type
519 int m_flags
; // bit mask of the value from the enum above
521 ArrayParamInfo m_params
;
524 WX_DEFINE_ARRAY(MethodInfo
*, ArrayMethodInfo
);
525 WX_DEFINE_ARRAY(ArrayMethodInfo
*, ArrayMethodInfos
);
527 // first array contains the names of all classes we found, the second has a
528 // pointer to the array of methods of the given class at the same index as
529 // the class name appears in m_classes
530 wxArrayString m_classes
;
531 ArrayMethodInfos m_methods
;
533 // are we checking parameter names?
534 bool m_checkParamNames
;
537 DocManager(const DocManager
&);
538 DocManager
& operator=(const DocManager
&);
541 // =============================================================================
543 // =============================================================================
545 // this function never returns
548 wxString prog
= wxTheApp
->argv
[0];
549 wxString basename
= prog
.AfterLast('/');
552 basename
= prog
.AfterLast('\\');
558 "usage: %s [global options] <mode> [mode options] <files...>\n"
560 " where global options are:\n"
563 " -H give this usage message\n"
564 " -V print the version info\n"
565 " -i file file with classes/function to ignore\n"
567 " where mode is one of: dump, diff\n"
569 " dump means generate .tex files for TeX2RTF converter from specified\n"
570 " headers files, mode options are:\n"
571 " -f overwrite existing files\n"
572 " -o outdir directory for generated files\n"
574 " diff means compare the set of methods documented .tex file with the\n"
575 " methods declared in the header:\n"
576 " %s diff <file.h> <files.tex...>.\n"
577 " mode specific options are:\n"
578 " -p do check parameter names (not done by default)\n"
579 "\n", basename
.c_str(), basename
.c_str());
584 int HelpGenApp::OnRun()
597 wxArrayString filesH
, filesTeX
;
598 wxString directoryOut
, // directory for 'dmup' output
599 ignoreFile
; // file with classes/functions to ignore
600 bool overwrite
= FALSE
, // overwrite existing files during 'dump'?
601 paramNames
= FALSE
; // check param names during 'diff'?
603 for ( int current
= 1; current
< argc
; current
++ ) {
604 // all options have one letter
605 if ( argv
[current
][0] == '-' ) {
606 if ( argv
[current
][2] == '\0' ) {
607 switch ( argv
[current
][1] ) {
610 wxLog::GetActiveTarget()->SetVerbose();
615 wxLog::GetActiveTarget()->SetVerbose(FALSE
);
625 wxLogMessage("HelpGen version %s\n"
626 "(c) 1999-2001 Vadim Zeitlin\n",
627 GetVersionString().c_str());
632 if ( current
>= argc
) {
633 wxLogError("-i option requires an argument.");
638 ignoreFile
= argv
[current
];
642 if ( mode
!= Mode_Diff
) {
643 wxLogError("-p is only valid with diff.");
652 if ( mode
!= Mode_Dump
) {
653 wxLogError("-f is only valid with dump.");
662 if ( mode
!= Mode_Dump
) {
663 wxLogError("-o is only valid with dump.");
669 if ( current
>= argc
) {
670 wxLogError("-o option requires an argument.");
675 directoryOut
= argv
[current
];
676 if ( !!directoryOut
) {
677 // terminate with a '/' if it doesn't have it
678 switch ( directoryOut
.Last() ) {
689 //else: it's empty, do nothing
694 wxLogError("unknown option '%s'", argv
[current
]);
699 wxLogError("only one letter options are allowed, not '%s'.",
703 // only get here after a break from switch or from else branch of if
708 if ( mode
== Mode_None
) {
709 if ( strcmp(argv
[current
], "diff") == 0 )
711 else if ( strcmp(argv
[current
], "dump") == 0 )
714 wxLogError("unknown mode '%s'.", argv
[current
]);
720 if ( mode
== Mode_Dump
|| filesH
.IsEmpty() ) {
721 filesH
.Add(argv
[current
]);
724 // 2nd files and further are TeX files in diff mode
725 wxASSERT( mode
== Mode_Diff
);
727 filesTeX
.Add(argv
[current
]);
733 // create a parser object and a visitor derivation
734 CJSourceParser parser
;
735 HelpGenVisitor
visitor(directoryOut
, overwrite
);
736 if ( !!ignoreFile
&& mode
== Mode_Dump
)
737 visitor
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
739 spContext
*ctxTop
= NULL
;
741 // parse all header files
742 size_t nFiles
= filesH
.GetCount();
743 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
744 wxString header
= filesH
[n
];
745 ctxTop
= parser
.ParseFile(header
);
747 wxLogWarning("Header file '%s' couldn't be processed.",
750 else if ( mode
== Mode_Dump
) {
751 ((spFile
*)ctxTop
)->mFileName
= header
;
752 visitor
.VisitAll(*ctxTop
);
759 #endif // __WXDEBUG__
762 // parse all TeX files
763 if ( mode
== Mode_Diff
) {
765 wxLogError("Can't complete diff.");
771 DocManager
docman(paramNames
);
773 size_t nFiles
= filesTeX
.GetCount();
774 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
775 wxString file
= filesTeX
[n
];
776 if ( !docman
.ParseTeXFile(file
) ) {
777 wxLogWarning("TeX file '%s' couldn't be processed.",
783 docman
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
785 docman
.DumpDifferences(ctxTop
);
791 int main(int argc
, char **argv
)
793 wxInitializer initializer
;
796 fprintf(stderr
, "Failed to initialize the wxWindows library, aborting.");
806 // -----------------------------------------------------------------------------
807 // HelpGenVisitor implementation
808 // -----------------------------------------------------------------------------
810 HelpGenVisitor::HelpGenVisitor(const wxString
& directoryOut
,
812 : m_directoryOut(directoryOut
)
814 m_overwrite
= overwrite
;
819 void HelpGenVisitor::Reset()
823 m_inMethodSection
= FALSE
;
828 m_textStoredTypedefs
=
829 m_textStoredFunctionComment
= "";
831 m_arrayFuncDocs
.Empty();
833 m_storedEnums
.Empty();
834 m_storedEnumsVerb
.Empty();
838 void HelpGenVisitor::InsertTypedefDocs()
840 m_file
.WriteTeX(m_textStoredTypedefs
);
841 m_textStoredTypedefs
.Empty();
844 void HelpGenVisitor::InsertEnumDocs()
846 size_t count
= m_storedEnums
.GetCount();
847 for ( size_t n
= 0; n
< count
; n
++ )
849 m_file
.WriteTeX(m_storedEnums
[n
]);
850 m_file
.WriteVerbatim(m_storedEnumsVerb
[n
] + '\n');
853 m_storedEnums
.Empty();
854 m_storedEnumsVerb
.Empty();
857 void HelpGenVisitor::InsertDataStructuresHeader()
859 if ( !m_inTypesSection
) {
860 m_inTypesSection
= TRUE
;
862 m_file
.WriteVerbatim("\\wxheading{Data structures}\n\n");
866 void HelpGenVisitor::InsertMethodsHeader()
868 if ( !m_inMethodSection
) {
869 m_inMethodSection
= TRUE
;
871 m_file
.WriteVerbatim( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
875 void HelpGenVisitor::CloseFunction()
877 if ( !m_funcName
.empty() ) {
878 if ( m_isFirstParam
) {
880 m_textFunc
<< "\\void";
883 m_textFunc
<< "}\n\n";
885 if ( !m_textStoredFunctionComment
.IsEmpty() ) {
886 m_textFunc
<< m_textStoredFunctionComment
<< '\n';
889 m_arrayFuncDocs
.Add(new FunctionDocEntry(m_funcName
, m_textFunc
));
895 void HelpGenVisitor::CloseClass()
900 size_t count
= m_arrayFuncDocs
.GetCount();
903 FunctionDocEntry::classname
= m_classname
;
905 m_arrayFuncDocs
.Sort(FunctionDocEntry::Compare
);
907 // Now examine each first line and if it's been seen, cut it
908 // off (it's a duplicate \membersection)
909 wxHashTable
membersections(wxKEY_STRING
);
911 for ( n
= 0; n
< count
; n
++ )
913 wxString
section(m_arrayFuncDocs
[n
].text
);
915 // Strip leading whitespace
916 int pos
= section
.Find("\\membersection");
919 section
= section
.Mid(pos
);
922 wxString
ms(section
.BeforeFirst(wxT('\n')));
923 if (membersections
.Get(ms
))
925 m_arrayFuncDocs
[n
].text
= section
.AfterFirst(wxT('\n'));
929 membersections
.Put(ms
, & membersections
);
933 for ( n
= 0; n
< count
; n
++ ) {
934 m_file
.WriteTeX(m_arrayFuncDocs
[n
].text
);
937 m_arrayFuncDocs
.Empty();
946 void HelpGenVisitor::EndVisit()
952 m_fileHeader
.Empty();
955 if (m_file
.IsOpened())
961 wxLogVerbose("%s: finished generating for the current file.",
962 GetCurrentTime("%H:%M:%S"));
965 void HelpGenVisitor::VisitFile( spFile
& file
)
967 m_fileHeader
= file
.mFileName
;
968 wxLogVerbose("%s: started generating docs for classes from file '%s'...",
969 GetCurrentTime("%H:%M:%S"), m_fileHeader
.c_str());
972 void HelpGenVisitor::VisitClass( spClass
& cl
)
976 if (m_file
.IsOpened())
982 wxString name
= cl
.GetName();
984 if ( m_ignoreNames
.IgnoreClass(name
) ) {
985 wxLogVerbose("Skipping ignored class '%s'.", name
.c_str());
990 // the file name is built from the class name by removing the leading "wx"
991 // if any and converting it to the lower case
993 if ( name(0, 2) == "wx" ) {
994 filename
<< name
.c_str() + 2;
1000 filename
.MakeLower();
1002 filename
.Prepend(m_directoryOut
);
1004 if ( !m_overwrite
&& wxFile::Exists(filename
) ) {
1005 wxLogError("Won't overwrite existing file '%s' - please use '-f'.",
1011 m_inClass
= m_file
.Open(filename
, wxFile::write
);
1013 wxLogError("Can't generate documentation for the class '%s'.",
1020 m_inTypesSection
= FALSE
;
1022 wxLogInfo("Created new file '%s' for class '%s'.",
1023 filename
.c_str(), name
.c_str());
1025 // write out the header
1027 header
.Printf("%%\n"
1028 "%% automatically generated by HelpGen %s from\n"
1033 "\\section{\\class{%s}}\\label{%s}\n\n",
1034 GetVersionString().c_str(),
1035 m_fileHeader
.c_str(),
1036 GetCurrentTime("%d/%b/%y %H:%M:%S"),
1038 wxString(name
).MakeLower().c_str());
1040 m_file
.WriteVerbatim(header
);
1042 // the entire text we're writing to file
1045 // if the header includes other headers they must be related to it... try to
1046 // automatically generate the "See also" clause
1047 if ( !m_headers
.IsEmpty() ) {
1048 // correspondence between wxWindows headers and class names
1049 static const char *headers
[] = {
1058 // NULL here means not to insert anything in "See also" for the
1059 // corresponding header
1060 static const char *classes
[] = {
1069 wxASSERT_MSG( WXSIZEOF(headers
) == WXSIZEOF(classes
),
1070 "arrays must be in sync!" );
1072 wxArrayInt interestingClasses
;
1074 size_t count
= m_headers
.Count(), index
;
1075 for ( size_t n
= 0; n
< count
; n
++ ) {
1076 wxString baseHeaderName
= m_headers
[n
].Before('.');
1077 if ( baseHeaderName(0, 3) != "wx/" )
1080 baseHeaderName
.erase(0, 3);
1081 for ( index
= 0; index
< WXSIZEOF(headers
); index
++ ) {
1082 if ( Stricmp(baseHeaderName
, headers
[index
]) == 0 )
1086 if ( (index
< WXSIZEOF(headers
)) && classes
[index
] ) {
1087 // interesting header
1088 interestingClasses
.Add(index
);
1092 if ( !interestingClasses
.IsEmpty() ) {
1093 // do generate "See also" clause
1094 totalText
<< "\\wxheading{See also:}\n\n";
1096 count
= interestingClasses
.Count();
1097 for ( index
= 0; index
< count
; index
++ ) {
1101 totalText
<< MakeHelpref(classes
[interestingClasses
[index
]]);
1104 totalText
<< "\n\n";
1108 // the comment before the class generally explains what is it for so put it
1109 // in place of the class description
1110 if ( cl
.HasComments() ) {
1111 wxString comment
= GetAllComments(cl
);
1113 totalText
<< '\n' << comment
<< '\n';
1116 // derived from section
1117 wxString derived
= "\\wxheading{Derived from}\n\n";
1119 const StrListT
& baseClasses
= cl
.mSuperClassNames
;
1120 if ( baseClasses
.size() == 0 ) {
1121 derived
<< "No base class";
1125 for ( StrListT::const_iterator i
= baseClasses
.begin();
1126 i
!= baseClasses
.end();
1129 // separate from the previous one
1130 derived
<< "\\\\\n";
1136 wxString baseclass
= *i
;
1137 derived
<< "\\helpref{" << baseclass
<< "}";
1138 derived
<< "{" << baseclass
.MakeLower() << "}";
1141 totalText
<< derived
<< "\n\n";
1143 // include file section
1144 wxString includeFile
= "\\wxheading{Include files}\n\n";
1145 includeFile
<< "<" << m_fileHeader
<< ">";
1147 totalText
<< includeFile
<< "\n\n";
1149 // write all this to file
1150 m_file
.WriteTeX(totalText
);
1152 // if there were any enums/typedefs before, insert their documentation now
1153 InsertDataStructuresHeader();
1154 InsertTypedefDocs();
1160 void HelpGenVisitor::VisitEnumeration( spEnumeration
& en
)
1164 if ( m_inMethodSection
) {
1165 // FIXME that's a bug, but tell the user aboit it nevertheless... we
1166 // should be smart enough to process even the enums which come after the
1168 wxLogWarning("enum '%s' ignored, please put it before the class "
1169 "methods.", en
.GetName().c_str());
1173 // simply copy the enum text in the docs
1174 wxString enumeration
= GetAllComments(en
),
1177 enumerationVerb
<< "\\begin{verbatim}\n"
1179 << "\n\\end{verbatim}\n";
1181 // remember for later use if we're not inside a class yet
1183 m_storedEnums
.Add(enumeration
);
1184 m_storedEnumsVerb
.Add(enumerationVerb
);
1187 // write the header for this section if not done yet
1188 InsertDataStructuresHeader();
1190 m_file
.WriteTeX(enumeration
);
1191 m_file
.WriteVerbatim(enumerationVerb
);
1192 m_file
.WriteVerbatim('\n');
1196 void HelpGenVisitor::VisitTypeDef( spTypeDef
& td
)
1200 if ( m_inMethodSection
) {
1201 // FIXME that's a bug, but tell the user aboit it nevertheless...
1202 wxLogWarning("typedef '%s' ignored, please put it before the class "
1203 "methods.", td
.GetName().c_str());
1207 wxString typedefdoc
;
1208 typedefdoc
<< "{\\small \\begin{verbatim}\n"
1209 << "typedef " << td
.mOriginalType
<< ' ' << td
.GetName()
1210 << "\n\\end{verbatim}}\n"
1211 << GetAllComments(td
);
1213 // remember for later use if we're not inside a class yet
1215 if ( !m_textStoredTypedefs
.IsEmpty() ) {
1216 m_textStoredTypedefs
<< '\n';
1219 m_textStoredTypedefs
<< typedefdoc
;
1222 // write the header for this section if not done yet
1223 InsertDataStructuresHeader();
1226 m_file
.WriteTeX(typedefdoc
);
1230 void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine
& pd
)
1232 switch ( pd
.GetStatementType() ) {
1233 case SP_PREP_DEF_INCLUDE_FILE
:
1234 m_headers
.Add(pd
.CPP_GetIncludedFileNeme());
1237 case SP_PREP_DEF_DEFINE_SYMBOL
:
1238 // TODO decide if it's a constant and document it if it is
1243 void HelpGenVisitor::VisitAttribute( spAttribute
& attr
)
1247 // only document the public member variables
1248 if ( !m_inClass
|| !attr
.IsPublic() )
1251 wxLogWarning("Ignoring member variable '%s'.", attr
.GetName().c_str());
1254 void HelpGenVisitor::VisitOperation( spOperation
& op
)
1259 // we don't generate docs right now - either we ignore this class
1260 // entirely or we couldn't open the file
1264 if ( !op
.IsInClass() ) {
1265 // TODO document global functions
1266 wxLogWarning("skipped global function '%s'.", op
.GetName().c_str());
1271 if ( op
.mVisibility
== SP_VIS_PRIVATE
) {
1272 // FIXME should we document protected functions?
1276 m_classname
= op
.GetClass().GetName();
1277 wxString funcname
= op
.GetName();
1279 if ( m_ignoreNames
.IgnoreMethod(m_classname
, funcname
) ) {
1280 wxLogVerbose("Skipping ignored '%s::%s'.",
1281 m_classname
.c_str(), funcname
.c_str());
1286 InsertMethodsHeader();
1289 m_funcName
= funcname
;
1290 m_isFirstParam
= TRUE
;
1292 m_textStoredFunctionComment
= GetAllComments(op
);
1294 // start function documentation
1297 // check for the special case of dtor
1299 if ( (funcname
[0] == '~') && (m_classname
== funcname
.c_str() + 1) ) {
1300 dtor
.Printf("\\destruct{%s}", m_classname
.c_str());
1304 m_textFunc
.Printf("\n"
1305 "\\membersection{%s::%s}\\label{%s}\n",
1306 m_classname
.c_str(), funcname
.c_str(),
1307 MakeLabel(m_classname
, funcname
).c_str());
1311 "\\%sfunc{%s%s}{%s}{",
1312 op
.mIsConstant
? "const" : "",
1313 op
.mIsVirtual
? "virtual " : "",
1314 op
.mRetType
.c_str(),
1319 void HelpGenVisitor::VisitParameter( spParameter
& param
)
1321 if ( m_funcName
.empty() )
1324 if ( m_isFirstParam
) {
1325 m_isFirstParam
= FALSE
;
1331 m_textFunc
<< "\\param{" << param
.mType
<< " }{" << param
.GetName();
1332 wxString defvalue
= param
.mInitVal
;
1333 if ( !defvalue
.IsEmpty() ) {
1334 m_textFunc
<< " = " << defvalue
;
1340 // ---------------------------------------------------------------------------
1342 // ---------------------------------------------------------------------------
1344 DocManager::DocManager(bool checkParamNames
)
1346 m_checkParamNames
= checkParamNames
;
1349 size_t DocManager::TryMatch(const char *str
, const char *match
)
1351 size_t lenMatch
= 0;
1352 while ( str
[lenMatch
] == match
[lenMatch
] ) {
1355 if ( match
[lenMatch
] == '\0' )
1362 bool DocManager::SkipUntil(const char **pp
, char c
)
1364 const char *p
= *pp
;
1380 bool DocManager::SkipSpaceUntil(const char **pp
, char c
)
1382 const char *p
= *pp
;
1384 if ( !isspace(*p
) || *p
== '\0' )
1398 wxString
DocManager::ExtractStringBetweenBraces(const char **pp
)
1402 if ( !SkipSpaceUntil(pp
, '{') ) {
1403 wxLogWarning("file %s(%d): '{' expected after '\\param'",
1404 m_filename
.c_str(), m_line
);
1408 const char *startParam
= ++*pp
; // skip '{'
1410 if ( !SkipUntil(pp
, '}') ) {
1411 wxLogWarning("file %s(%d): '}' expected after '\\param'",
1412 m_filename
.c_str(), m_line
);
1415 result
= wxString(startParam
, (*pp
)++ - startParam
);
1422 bool DocManager::ParseTeXFile(const wxString
& filename
)
1424 m_filename
= filename
;
1426 wxFile
file(m_filename
, wxFile::read
);
1427 if ( !file
.IsOpened() )
1430 off_t len
= file
.Length();
1431 if ( len
== wxInvalidOffset
)
1434 char *buf
= new char[len
+ 1];
1437 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1443 // reinit everything
1446 wxLogVerbose("%s: starting to parse doc file '%s'.",
1447 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1449 // the name of the class from the last "\membersection" command: we assume
1450 // that the following "\func" or "\constfunc" always documents a method of
1451 // this class (and it should always be like that in wxWindows documentation)
1454 for ( const char *current
= buf
; current
- buf
< len
; current
++ ) {
1455 // FIXME parsing is awfully inefficient
1457 if ( *current
== '%' ) {
1458 // comment, skip until the end of line
1460 SkipUntil(¤t
, '\n');
1465 // all the command we're interested in start with '\\'
1466 while ( *current
!= '\\' && *current
!= '\0' ) {
1467 if ( *current
++ == '\n' )
1471 if ( *current
== '\0' ) {
1472 // no more TeX commands left
1476 current
++; // skip '\\'
1484 } foundCommand
= Nothing
;
1486 size_t lenMatch
= TryMatch(current
, "func");
1488 foundCommand
= Func
;
1491 lenMatch
= TryMatch(current
, "constfunc");
1493 foundCommand
= ConstFunc
;
1495 lenMatch
= TryMatch(current
, "membersection");
1498 foundCommand
= MemberSect
;
1502 if ( foundCommand
== Nothing
)
1505 current
+= lenMatch
;
1507 if ( !SkipSpaceUntil(¤t
, '{') ) {
1508 wxLogWarning("file %s(%d): '{' expected after \\func, "
1509 "\\constfunc or \\membersection.",
1510 m_filename
.c_str(), m_line
);
1517 if ( foundCommand
== MemberSect
) {
1518 // what follows has the form <classname>::<funcname>
1519 const char *startClass
= current
;
1520 if ( !SkipUntil(¤t
, ':') || *(current
+ 1) != ':' ) {
1521 wxLogWarning("file %s(%d): '::' expected after "
1522 "\\membersection.", m_filename
.c_str(), m_line
);
1525 classname
= wxString(startClass
, current
- startClass
);
1526 TeXUnfilter(&classname
);
1532 // extract the return type
1533 const char *startRetType
= current
;
1535 if ( !SkipUntil(¤t
, '}') ) {
1536 wxLogWarning("file %s(%d): '}' expected after return type",
1537 m_filename
.c_str(), m_line
);
1542 wxString returnType
= wxString(startRetType
, current
- startRetType
);
1543 TeXUnfilter(&returnType
);
1546 if ( !SkipSpaceUntil(¤t
, '{') ) {
1547 wxLogWarning("file %s(%d): '{' expected after return type",
1548 m_filename
.c_str(), m_line
);
1554 const char *funcEnd
= current
;
1555 if ( !SkipUntil(&funcEnd
, '}') ) {
1556 wxLogWarning("file %s(%d): '}' expected after function name",
1557 m_filename
.c_str(), m_line
);
1562 wxString funcName
= wxString(current
, funcEnd
- current
);
1563 current
= funcEnd
+ 1;
1565 // trim spaces from both sides
1566 funcName
.Trim(FALSE
);
1567 funcName
.Trim(TRUE
);
1569 // special cases: '$...$' may be used for LaTeX inline math, remove the
1571 if ( funcName
.Find('$') != wxNOT_FOUND
) {
1573 for ( const char *p
= funcName
.c_str(); *p
!= '\0'; p
++ ) {
1574 if ( *p
!= '$' && !isspace(*p
) )
1581 // \destruct{foo} is really ~foo
1582 if ( funcName
[0u] == '\\' ) {
1583 size_t len
= strlen("\\destruct{");
1584 if ( funcName(0, len
) != "\\destruct{" ) {
1585 wxLogWarning("file %s(%d): \\destruct expected",
1586 m_filename
.c_str(), m_line
);
1591 funcName
.erase(0, len
);
1592 funcName
.Prepend('~');
1594 if ( !SkipSpaceUntil(¤t
, '}') ) {
1595 wxLogWarning("file %s(%d): '}' expected after destructor",
1596 m_filename
.c_str(), m_line
);
1601 funcEnd
++; // there is an extra '}' to count
1604 TeXUnfilter(&funcName
);
1607 current
= funcEnd
+ 1; // skip '}'
1608 if ( !SkipSpaceUntil(¤t
, '{') ||
1609 (current
++, !SkipSpaceUntil(¤t
, '\\')) ) {
1610 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1611 m_filename
.c_str(), m_line
);
1616 wxArrayString paramNames
, paramTypes
, paramValues
;
1618 bool isVararg
= FALSE
;
1620 current
++; // skip '\\'
1621 lenMatch
= TryMatch(current
, "void");
1623 lenMatch
= TryMatch(current
, "param");
1624 while ( lenMatch
&& (current
- buf
< len
) ) {
1625 current
+= lenMatch
;
1627 // now come {paramtype}{paramname}
1628 wxString paramType
= ExtractStringBetweenBraces(¤t
);
1629 if ( !!paramType
) {
1630 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1631 if ( !!paramText
) {
1632 // the param declaration may contain default value
1633 wxString paramName
= paramText
.BeforeFirst('='),
1634 paramValue
= paramText
.AfterFirst('=');
1636 // sanitize all strings
1637 TeXUnfilter(¶mValue
);
1638 TeXUnfilter(¶mName
);
1639 TeXUnfilter(¶mType
);
1641 paramValues
.Add(paramValue
);
1642 paramNames
.Add(paramName
);
1643 paramTypes
.Add(paramType
);
1648 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1649 if ( paramText
== "..." ) {
1653 wxLogWarning("Parameters of '%s::%s' are in "
1655 classname
.c_str(), funcName
.c_str());
1660 current
= SkipSpaces(current
);
1661 if ( *current
== ',' || *current
== '}' ) {
1662 current
= SkipSpaces(++current
);
1664 lenMatch
= TryMatch(current
, "\\param");
1667 wxLogWarning("file %s(%d): ',' or '}' expected after "
1668 "'\\param'", m_filename
.c_str(), m_line
);
1674 // if we got here there was no '\\void', so must have some params
1675 if ( paramNames
.IsEmpty() ) {
1676 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1677 m_filename
.c_str(), m_line
);
1683 // verbose diagnostic output
1685 size_t param
, paramCount
= paramNames
.GetCount();
1686 for ( param
= 0; param
< paramCount
; param
++ ) {
1691 paramsAll
<< paramTypes
[param
] << ' ' << paramNames
[param
];
1694 wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
1695 m_filename
.c_str(), m_line
,
1700 foundCommand
== ConstFunc
? " const" : "");
1702 // store the info about the just found function
1703 ArrayMethodInfo
*methods
;
1704 int index
= m_classes
.Index(classname
);
1705 if ( index
== wxNOT_FOUND
) {
1706 m_classes
.Add(classname
);
1708 methods
= new ArrayMethodInfo
;
1709 m_methods
.Add(methods
);
1712 methods
= m_methods
[(size_t)index
];
1715 ArrayParamInfo params
;
1716 for ( param
= 0; param
< paramCount
; param
++ ) {
1717 params
.Add(new ParamInfo(paramTypes
[param
],
1719 paramValues
[param
]));
1722 MethodInfo
*method
= new MethodInfo(returnType
, funcName
, params
);
1723 if ( foundCommand
== ConstFunc
)
1724 method
->SetFlag(MethodInfo::Const
);
1726 method
->SetFlag(MethodInfo::Vararg
);
1728 methods
->Add(method
);
1733 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1734 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1739 bool DocManager::DumpDifferences(spContext
*ctxTop
) const
1741 typedef MMemberListT::const_iterator MemberIndex
;
1743 bool foundDiff
= FALSE
;
1745 // flag telling us whether the given class was found at all in the header
1746 size_t nClass
, countClassesInDocs
= m_classes
.GetCount();
1747 bool *classExists
= new bool[countClassesInDocs
];
1748 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1749 classExists
[nClass
] = FALSE
;
1752 // ctxTop is normally an spFile
1753 wxASSERT( ctxTop
->GetContextType() == SP_CTX_FILE
);
1755 const MMemberListT
& classes
= ctxTop
->GetMembers();
1756 for ( MemberIndex i
= classes
.begin(); i
!= classes
.end(); i
++ ) {
1757 spContext
*ctx
= *i
;
1758 if ( ctx
->GetContextType() != SP_CTX_CLASS
) {
1759 // TODO process also global functions, macros, ...
1763 spClass
*ctxClass
= (spClass
*)ctx
;
1764 const wxString
& nameClass
= ctxClass
->mName
;
1765 int index
= m_classes
.Index(nameClass
);
1766 if ( index
== wxNOT_FOUND
) {
1767 if ( !m_ignoreNames
.IgnoreClass(nameClass
) ) {
1770 wxLogError("Class '%s' is not documented at all.",
1774 // it makes no sense to check for its functions
1778 classExists
[index
] = TRUE
;
1781 // array of method descriptions for this class
1782 const ArrayMethodInfo
& methods
= *(m_methods
[index
]);
1783 size_t nMethod
, countMethods
= methods
.GetCount();
1785 // flags telling if we already processed given function
1786 bool *methodExists
= new bool[countMethods
];
1787 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1788 methodExists
[nMethod
] = FALSE
;
1791 wxArrayString aOverloadedMethods
;
1793 const MMemberListT
& functions
= ctxClass
->GetMembers();
1794 for ( MemberIndex j
= functions
.begin(); j
!= functions
.end(); j
++ ) {
1796 if ( ctx
->GetContextType() != SP_CTX_OPERATION
)
1799 spOperation
*ctxMethod
= (spOperation
*)ctx
;
1800 const wxString
& nameMethod
= ctxMethod
->mName
;
1802 // find all functions with the same name
1803 wxArrayInt aMethodsWithSameName
;
1804 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1805 if ( methods
[nMethod
]->GetName() == nameMethod
)
1806 aMethodsWithSameName
.Add(nMethod
);
1809 if ( aMethodsWithSameName
.IsEmpty() && ctxMethod
->IsPublic() ) {
1810 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1813 wxLogError("'%s::%s' is not documented.",
1815 nameMethod
.c_str());
1818 // don't check params
1821 else if ( aMethodsWithSameName
.GetCount() == 1 ) {
1822 index
= (size_t)aMethodsWithSameName
[0u];
1823 methodExists
[index
] = TRUE
;
1825 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1828 if ( !ctxMethod
->IsPublic() ) {
1829 wxLogWarning("'%s::%s' is documented but not public.",
1831 nameMethod
.c_str());
1834 // check that the flags match
1835 const MethodInfo
& method
= *(methods
[index
]);
1837 bool isVirtual
= ctxMethod
->mIsVirtual
;
1838 if ( isVirtual
!= method
.HasFlag(MethodInfo::Virtual
) ) {
1839 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1843 isVirtual
? "not " : "");
1846 bool isConst
= ctxMethod
->mIsConstant
;
1847 if ( isConst
!= method
.HasFlag(MethodInfo::Const
) ) {
1848 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1852 isConst
? "not " : "");
1855 // check that the params match
1856 const MMemberListT
& params
= ctxMethod
->GetMembers();
1858 if ( params
.size() != method
.GetParamCount() ) {
1859 wxLogError("Incorrect number of parameters for '%s::%s' "
1860 "in the docs: should be %d instead of %d.",
1863 params
.size(), method
.GetParamCount());
1867 for ( MemberIndex k
= params
.begin();
1872 // what else can a function have?
1873 wxASSERT( ctx
->GetContextType() == SP_CTX_PARAMETER
);
1875 spParameter
*ctxParam
= (spParameter
*)ctx
;
1876 const ParamInfo
& param
= method
.GetParam(nParam
);
1877 if ( m_checkParamNames
&&
1878 (param
.GetName() != ctxParam
->mName
) ) {
1881 wxLogError("Parameter #%d of '%s::%s' should be "
1882 "'%s' and not '%s'.",
1886 ctxParam
->mName
.c_str(),
1887 param
.GetName().c_str());
1892 if ( param
.GetType() != ctxParam
->mType
) {
1895 wxLogError("Type of parameter '%s' of '%s::%s' "
1896 "should be '%s' and not '%s'.",
1897 ctxParam
->mName
.c_str(),
1900 ctxParam
->mType
.c_str(),
1901 param
.GetType().GetName().c_str());
1906 if ( param
.GetDefValue() != ctxParam
->mInitVal
) {
1907 wxLogWarning("Default value of parameter '%s' of "
1908 "'%s::%s' should be '%s' and not "
1910 ctxParam
->mName
.c_str(),
1913 ctxParam
->mInitVal
.c_str(),
1914 param
.GetDefValue().c_str());
1920 // TODO OVER add real support for overloaded methods
1922 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1925 if ( aOverloadedMethods
.Index(nameMethod
) == wxNOT_FOUND
) {
1926 // mark all methods with this name as existing
1927 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1928 if ( methods
[nMethod
]->GetName() == nameMethod
)
1929 methodExists
[nMethod
] = TRUE
;
1932 aOverloadedMethods
.Add(nameMethod
);
1934 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1935 "stupid to find the right match - skipping "
1936 "the param and flags checks.",
1938 nameMethod
.c_str());
1940 //else: warning already given
1944 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1945 if ( !methodExists
[nMethod
] ) {
1946 const wxString
& nameMethod
= methods
[nMethod
]->GetName();
1947 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1950 wxLogError("'%s::%s' is documented but doesn't exist.",
1952 nameMethod
.c_str());
1957 delete [] methodExists
;
1960 // check that all classes we found in the docs really exist
1961 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1962 if ( !classExists
[nClass
] ) {
1965 wxLogError("Class '%s' is documented but doesn't exist.",
1966 m_classes
[nClass
].c_str());
1970 delete [] classExists
;
1975 DocManager::~DocManager()
1977 WX_CLEAR_ARRAY(m_methods
);
1980 // ---------------------------------------------------------------------------
1981 // IgnoreNamesHandler implementation
1982 // ---------------------------------------------------------------------------
1984 int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry
*first
,
1985 IgnoreListEntry
*second
)
1987 // first compare the classes
1988 int rc
= first
->m_classname
.Cmp(second
->m_classname
);
1990 rc
= first
->m_funcname
.Cmp(second
->m_funcname
);
1995 bool IgnoreNamesHandler::AddNamesFromFile(const wxString
& filename
)
1997 wxFile
file(filename
, wxFile::read
);
1998 if ( !file
.IsOpened() )
2001 off_t len
= file
.Length();
2002 if ( len
== wxInvalidOffset
)
2005 char *buf
= new char[len
+ 1];
2008 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
2015 for ( const char *current
= buf
; ; current
++ ) {
2017 // skip DOS line separator
2018 if ( *current
== '\r' )
2022 if ( *current
== '\n' || *current
== '\0' ) {
2023 if ( line
[0u] != '#' ) {
2024 if ( line
.Find(':') != wxNOT_FOUND
) {
2025 wxString classname
= line
.BeforeFirst(':'),
2026 funcname
= line
.AfterLast(':');
2027 m_ignore
.Add(new IgnoreListEntry(classname
, funcname
));
2031 m_ignore
.Add(new IgnoreListEntry(line
, ""));
2036 if ( *current
== '\0' )
2051 // -----------------------------------------------------------------------------
2052 // global function implementation
2053 // -----------------------------------------------------------------------------
2055 static wxString
MakeLabel(const char *classname
, const char *funcname
)
2057 wxString
label(classname
);
2058 if ( funcname
&& funcname
[0] == '\\' ) {
2059 // we may have some special TeX macro - so far only \destruct exists,
2060 // but may be later others will be added
2061 static const char *macros
[] = { "destruct" };
2062 static const char *replacement
[] = { "dtor" };
2065 for ( n
= 0; n
< WXSIZEOF(macros
); n
++ ) {
2066 if ( strncmp(funcname
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) {
2072 if ( n
== WXSIZEOF(macros
) ) {
2073 wxLogWarning("unknown function name '%s' - leaving as is.",
2077 funcname
= replacement
[n
];
2082 // special treatment for operatorXXX() stuff because the C operators
2083 // are not valid in LaTeX labels
2085 if ( wxString(funcname
).StartsWith("operator", &oper
) ) {
2086 label
<< "operator";
2099 for ( n
= 0; n
< WXSIZEOF(operatorNames
); n
++ ) {
2100 if ( oper
== operatorNames
[n
].oper
) {
2101 label
<< operatorNames
[n
].name
;
2107 if ( n
== WXSIZEOF(operatorNames
) ) {
2108 wxLogWarning("unknown operator '%s' - making dummy label.",
2114 else // simply use the func name
2125 static wxString
MakeHelpref(const char *argument
)
2128 helpref
<< "\\helpref{" << argument
<< "}{" << MakeLabel(argument
) << '}';
2133 static void TeXFilter(wxString
* str
)
2135 // TeX special which can be quoted (don't include backslash nor braces as
2137 static wxRegEx
reNonSpecialSpecials("[#$%&_]"),
2141 reNonSpecialSpecials
.ReplaceAll(str
, "\\\\\\0");
2143 // can't quote these ones as they produce accents when preceded by
2144 // backslash, so put them inside verb
2145 reAccents
.ReplaceAll(str
, "\\\\verb|\\0|");
2148 static void TeXUnfilter(wxString
* str
)
2150 // FIXME may be done much more quickly
2155 static wxRegEx
reNonSpecialSpecials("\\\\([#$%&_{}])"),
2156 reAccents("\\\\verb|([~^])|");
2158 reNonSpecialSpecials
.ReplaceAll(str
, "\\1");
2159 reAccents
.ReplaceAll(str
, "\\1");
2162 static wxString
GetAllComments(const spContext
& ctx
)
2165 const MCommentListT
& commentsList
= ctx
.GetCommentList();
2166 for ( MCommentListT::const_iterator i
= commentsList
.begin();
2167 i
!= commentsList
.end();
2169 wxString comment
= (*i
)->GetText();
2171 // don't take comments like "// ----------" &c
2172 comment
.Trim(FALSE
);
2174 comment
== wxString(comment
[0u], comment
.length() - 1) + '\n' )
2177 comments
<< comment
;
2183 static const char *GetCurrentTime(const char *timeFormat
)
2185 static char s_timeBuffer
[128];
2190 ptmNow
= localtime(&timeNow
);
2192 strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
);
2194 return s_timeBuffer
;
2197 static const wxString
GetVersionString()
2199 wxString version
= "$Revision$";
2200 wxRegEx("^\\$Revision$$").ReplaceFirst(&version
, "\\1");
2206 Revision 1.22 2002/01/21 21:18:50 JS
2207 Now adds 'include file' heading
2209 Revision 1.21 2002/01/04 11:06:09 JS
2210 Fixed missing membersections bug and also bug with functions not being written
2213 Revision 1.20 2002/01/03 14:23:33 JS
2214 Added code to make it not duplicate membersections for overloaded functions
2216 Revision 1.19 2002/01/03 13:34:12 JS
2217 Added FlushAll to CloseClass, otherwise text was only flushed right at the end,
2218 and appeared in one file.
2220 Revision 1.18 2002/01/03 12:02:47 JS
2221 Added main() and corrected VC++ project settings
2223 Revision 1.17 2001/11/30 21:43:35 VZ
2224 now the methods are sorted in the correct order in the generated docs
2226 Revision 1.16 2001/11/28 19:27:33 VZ
2227 HelpGen doesn't work in GUI mode
2229 Revision 1.15 2001/11/22 21:59:58 GD
2230 use "..." instead of <...> for wx headers
2232 Revision 1.14 2001/07/19 13:51:29 VZ
2233 fixes to version string
2235 Revision 1.13 2001/07/19 13:44:57 VZ
2236 1. compilation fixes
2237 2. don't quote special characters inside verbatim environment
2239 Revision 1.12 2000/10/09 13:53:33 juliansmart
2241 Doc corrections; added HelpGen project files
2243 Revision 1.11 2000/07/15 19:50:42 cvsuser
2246 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
2247 don't trasnform output dir name to lower case
2249 Revision 1.10 2000/03/11 10:05:23 VS
2250 now compiles with wxBase
2252 Revision 1.9 2000/01/16 13:25:21 VS
2253 compilation fixes (gcc)
2255 Revision 1.8 1999/09/13 14:29:39 JS
2257 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2258 into src for simplicity; added VC++ 5 project file
2260 Revision 1.7 1999/02/21 22:32:32 VZ
2261 1. more C++ parser fixes - now it almost parses wx/string.h
2262 a) #if/#ifdef/#else (very) limited support
2263 b) param type fix - now indirection chars are correctly handled
2264 c) class/struct/union distinction
2265 d) public/private fixes
2266 e) Dump() function added - very useful for debugging
2268 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2269 by default, and this option switches it on)
2271 Revision 1.6 1999/02/20 23:00:26 VZ
2272 1. new 'diff' mode which seems to work
2273 2. output files are not overwritten in 'dmup' mode
2274 3. fixes for better handling of const functions and operators
2275 ----------------------------
2277 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2278 1. Parser improvements
2279 a) const and virtual methods are parsed correctly (not static yet)
2280 b) "const" which is part of the return type is not swallowed
2282 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2283 "//---------" kind comments discarded now.
2284 ----------------------------
2286 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2288 some tweaks to HelpGen
2289 ----------------------------
2291 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2293 HelpGen starting to compile with VC++
2294 ----------------------------
2296 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2298 supports typedefs, generates "See also:" and adds "virtual " for virtual
2300 ----------------------------
2302 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2304 HelpGen is a prototype of the tool for automatic generation of the .tex files
2305 for wxWindows documentation from C++ headers
2308 /* vi: set tw=80 et ts=4 sw=4: */