1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Main program file for HelpGen
4 // Author: Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Copyright: (c) 1999 VZ
9 // Licence: wxWindows Licence
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"
59 #error "HelpGen doesn't build in Unicode mode"
63 #include "wx/string.h"
65 #include "wx/dynarray.h"
73 // C++ parsing classes
80 // -----------------------------------------------------------------------------
82 // -----------------------------------------------------------------------------
84 // return the label for the given function name (i.e. argument of \label)
85 static wxString
MakeLabel(const wxChar
*classname
, const wxChar
*funcname
= NULL
);
87 // return the whole \helpref{arg}{arg_label} string
88 static wxString
MakeHelpref(const wxChar
*argument
);
90 // [un]quote special TeX characters (in place)
91 static void TeXFilter(wxString
* str
);
92 static void TeXUnfilter(wxString
* str
); // also trims spaces
94 // get all comments associated with this context
95 static wxString
GetAllComments(const spContext
& ctx
);
97 // get the string with current time (returns pointer to static buffer)
98 // timeFormat is used for the call of strftime(3)
99 static const char *GetCurrentTimeFormatted(const char *timeFormat
);
101 // get the string containing the program version
102 static const wxString
GetVersionString();
104 // -----------------------------------------------------------------------------
106 // -----------------------------------------------------------------------------
108 // a function documentation entry
109 struct FunctionDocEntry
111 FunctionDocEntry(const wxString
& name_
, const wxString
& text_
)
112 : name(name_
), text(text_
) { }
117 // the function doc text
121 static int Compare(FunctionDocEntry
**pp1
, FunctionDocEntry
**pp2
)
123 // the methods should appear in the following order: ctors, dtor, all
124 // the rest in the alphabetical order
125 bool isCtor1
= (*pp1
)->name
== classname
;
126 bool isCtor2
= (*pp2
)->name
== classname
;
130 // we don't order the ctors because we don't know how to do it
134 // ctor comes before non-ctor
139 // non-ctor must come after ctor
143 wxString dtorname
= wxString(_T("~")) + classname
;
145 // there is only one dtor, so the logic here is simpler
146 if ( (*pp1
)->name
== dtorname
) {
149 else if ( (*pp2
)->name
== dtorname
) {
153 // two normal methods
154 return wxStrcmp((*pp1
)->name
, (*pp2
)->name
);
158 static wxString classname
;
161 wxString
FunctionDocEntry::classname
;
163 WX_DECLARE_OBJARRAY(FunctionDocEntry
, FunctionDocEntries
);
165 #include "wx/arrimpl.cpp"
167 WX_DEFINE_OBJARRAY(FunctionDocEntries
);
169 // add a function which sanitazes the string before writing it to the file and
170 // also capable of delaying output and sorting it before really writing it to
171 // the file (done from FlushAll())
172 class wxTeXFile
: public wxFile
177 // write a string to file verbatim (should only be used for the strings
178 // inside verbatim environment)
179 void WriteVerbatim(const wxString
& s
)
184 // write a string quoting TeX specials in it
185 void WriteTeX(const wxString
& s
)
193 // do write everything to file
196 if ( m_text
.empty() )
199 if ( !Write(m_text
) ) {
200 wxLogError(_T("Failed to output generated documentation."));
211 wxTeXFile(const wxTeXFile
&);
212 wxTeXFile
& operator=(const wxTeXFile
&);
217 // helper class which manages the classes and function names to ignore for
218 // the documentation purposes (used by both HelpGenVisitor and DocManager)
219 class IgnoreNamesHandler
222 IgnoreNamesHandler() : m_ignore(CompareIgnoreListEntries
) { }
223 ~IgnoreNamesHandler() { WX_CLEAR_ARRAY(m_ignore
); }
225 // load file with classes/functions to ignore (add them to the names we
227 bool AddNamesFromFile(const wxString
& filename
);
229 // return true if we ignore this function
230 bool IgnoreMethod(const wxString
& classname
,
231 const wxString
& funcname
) const
233 if ( IgnoreClass(classname
) )
236 IgnoreListEntry
ignore(classname
, funcname
);
238 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
241 // return true if we ignore this class entirely
242 bool IgnoreClass(const wxString
& classname
) const
244 IgnoreListEntry
ignore(classname
, _T(""));
246 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
250 struct IgnoreListEntry
252 IgnoreListEntry(const wxString
& classname
,
253 const wxString
& funcname
)
254 : m_classname(classname
), m_funcname(funcname
)
258 wxString m_classname
;
259 wxString m_funcname
; // if empty, ignore class entirely
262 static int CompareIgnoreListEntries(IgnoreListEntry
*first
,
263 IgnoreListEntry
*second
);
265 // for efficiency, let's sort it
266 public: // FIXME: macro requires it
267 WX_DEFINE_SORTED_ARRAY(IgnoreListEntry
*, ArrayNamesToIgnore
);
270 ArrayNamesToIgnore m_ignore
;
273 IgnoreNamesHandler(const IgnoreNamesHandler
&);
274 IgnoreNamesHandler
& operator=(const IgnoreNamesHandler
&);
277 // visitor implementation which writes all collected data to a .tex file
278 class HelpGenVisitor
: public spVisitor
282 HelpGenVisitor(const wxString
& directoryOut
, bool overwrite
);
284 virtual void VisitFile( spFile
& fl
);
285 virtual void VisitClass( spClass
& cl
);
286 virtual void VisitEnumeration( spEnumeration
& en
);
287 virtual void VisitTypeDef( spTypeDef
& td
);
288 virtual void VisitPreprocessorLine( spPreprocessorLine
& pd
);
289 virtual void VisitAttribute( spAttribute
& attr
);
290 virtual void VisitOperation( spOperation
& op
);
291 virtual void VisitParameter( spParameter
& param
);
295 // get our `ignore' object
296 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
298 // shut up g++ warning (ain't it stupid?)
299 virtual ~HelpGenVisitor() { }
302 // (re)initialize the state
305 // insert documentation for enums/typedefs coming immediately before the
306 // class declaration into the class documentation
307 void InsertTypedefDocs();
308 void InsertEnumDocs();
310 // write the headers for corresponding sections (only once)
311 void InsertDataStructuresHeader();
312 void InsertMethodsHeader();
314 // terminate the function documentation if it was started
315 void CloseFunction();
317 // write out all function docs when there are no more left in this class
318 // after sorting them in alphabetical order
321 wxString m_directoryOut
, // directory for the output
322 m_fileHeader
; // name of the .h file we parse
323 bool m_overwrite
; // overwrite existing files?
324 wxTeXFile m_file
; // file we're writing to now
327 bool m_inClass
, // true after file successfully opened
328 m_inTypesSection
, // enums & typedefs go there
329 m_inMethodSection
, // functions go here
330 m_isFirstParam
; // first parameter of current function?
332 // non empty while parsing a class
333 wxString m_classname
;
335 // these are only non-empty while parsing a method:
336 wxString m_funcName
, // the function name
337 m_textFunc
; // the function doc text
339 // the array containing the documentation entries for the functions in the
340 // class currently being parsed
341 FunctionDocEntries m_arrayFuncDocs
;
343 // holders for "saved" documentation
344 wxString m_textStoredTypedefs
,
345 m_textStoredFunctionComment
;
347 // for enums we have to use an array as we can't intermix the normal text
348 // and the text inside verbatim environment
349 wxArrayString m_storedEnums
,
352 // headers included by this file
353 wxArrayString m_headers
;
355 // ignore handler: tells us which classes to ignore for doc generation
357 IgnoreNamesHandler m_ignoreNames
;
360 HelpGenVisitor(const HelpGenVisitor
&);
361 HelpGenVisitor
& operator=(const HelpGenVisitor
&);
364 // documentation manager - a class which parses TeX files and remembers the
365 // functions documented in them and can later compare them with all functions
366 // found under ctxTop by C++ parser
370 DocManager(bool checkParamNames
);
373 // returns false on failure
374 bool ParseTeXFile(const wxString
& filename
);
376 // returns false if there were any differences
377 bool DumpDifferences(spContext
*ctxTop
) const;
379 // get our `ignore' object
380 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
386 // returns the length of 'match' if the string 'str' starts with it or 0
388 static size_t TryMatch(const wxChar
*str
, const wxChar
*match
);
390 // skip spaces: returns pointer to first non space character (also
391 // updates the value of m_line)
392 const char *SkipSpaces(const char *p
)
394 while ( isspace(*p
) ) {
402 // skips characters until the next 'c' in '*pp' unless it ends before in
403 // which case false is returned and pp points to '\0', otherwise true is
404 // returned and pp points to 'c'
405 bool SkipUntil(const char **pp
, char c
);
407 // the same as SkipUntil() but only spaces are skipped: on first non space
408 // character different from 'c' the function stops and returns false
409 bool SkipSpaceUntil(const char **pp
, char c
);
411 // extract the string between {} and modify '*pp' to point at the
412 // character immediately after the closing '}'. The returned string is empty
414 wxString
ExtractStringBetweenBraces(const char **pp
);
416 // the current file and line while we're in ParseTeXFile (for error
421 // functions and classes to ignore during diff
422 // -------------------------------------------
424 IgnoreNamesHandler m_ignoreNames
;
426 // information about all functions documented in the TeX file(s)
427 // -------------------------------------------------------------
429 // info about a type: for now stored as text string, but must be parsed
430 // further later (to know that "char *" == "char []" - TODO)
434 TypeInfo(const wxString
& type
) : m_type(type
) { }
436 bool operator==(const wxString
& type
) const { return m_type
== type
; }
437 bool operator!=(const wxString
& type
) const { return m_type
!= type
; }
439 const wxString
& GetName() const { return m_type
; }
445 friend class ParamInfo
; // for access to TypeInfo
447 // info abotu a function parameter
451 ParamInfo(const wxString
& type
,
452 const wxString
& name
,
453 const wxString
& value
)
454 : m_type(type
), m_name(name
), m_value(value
)
458 const TypeInfo
& GetType() const { return m_type
; }
459 const wxString
& GetName() const { return m_name
; }
460 const wxString
& GetDefValue() const { return m_value
; }
463 TypeInfo m_type
; // type of parameter
464 wxString m_name
; // name
465 wxString m_value
; // default value
468 public: // FIXME: macro requires it
469 WX_DEFINE_ARRAY_PTR(ParamInfo
*, ArrayParamInfo
);
471 // info about a function
484 MethodInfo(const wxString
& type
,
485 const wxString
& name
,
486 const ArrayParamInfo
& params
)
487 : m_typeRet(type
), m_name(name
), m_params(params
)
492 void SetFlag(MethodFlags flag
) { m_flags
|= flag
; }
494 const TypeInfo
& GetType() const { return m_typeRet
; }
495 const wxString
& GetName() const { return m_name
; }
496 const ParamInfo
& GetParam(size_t n
) const { return *(m_params
[n
]); }
497 size_t GetParamCount() const { return m_params
.GetCount(); }
499 bool HasFlag(MethodFlags flag
) const { return (m_flags
& flag
) != 0; }
501 ~MethodInfo() { WX_CLEAR_ARRAY(m_params
); }
504 TypeInfo m_typeRet
; // return type
506 int m_flags
; // bit mask of the value from the enum above
508 ArrayParamInfo m_params
;
511 WX_DEFINE_ARRAY_PTR(MethodInfo
*, ArrayMethodInfo
);
512 WX_DEFINE_ARRAY_PTR(ArrayMethodInfo
*, ArrayMethodInfos
);
515 // first array contains the names of all classes we found, the second has a
516 // pointer to the array of methods of the given class at the same index as
517 // the class name appears in m_classes
518 wxArrayString m_classes
;
519 ArrayMethodInfos m_methods
;
521 // are we checking parameter names?
522 bool m_checkParamNames
;
525 DocManager(const DocManager
&);
526 DocManager
& operator=(const DocManager
&);
529 // =============================================================================
531 // =============================================================================
533 static char **g_argv
= NULL
;
535 // this function never returns
538 wxString prog
= g_argv
[0];
539 wxString basename
= prog
.AfterLast('/');
542 basename
= prog
.AfterLast('\\');
548 "usage: %s [global options] <mode> [mode options] <files...>\n"
550 " where global options are:\n"
553 " -H give this usage message\n"
554 " -V print the version info\n"
555 " -i file file with classes/function to ignore\n"
557 " where mode is one of: dump, diff\n"
559 " dump means generate .tex files for TeX2RTF converter from specified\n"
560 " headers files, mode options are:\n"
561 " -f overwrite existing files\n"
562 " -o outdir directory for generated files\n"
564 " diff means compare the set of methods documented .tex file with the\n"
565 " methods declared in the header:\n"
566 " %s diff <file.h> <files.tex...>.\n"
567 " mode specific options are:\n"
568 " -p do check parameter names (not done by default)\n"
569 "\n", basename
.c_str(), basename
.c_str());
574 int main(int argc
, char **argv
)
578 wxInitializer initializer
;
581 fprintf(stderr
, "Failed to initialize the wxWidgets library, aborting.");
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
.IsEmpty() ) {
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
.IsEmpty() && 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.",
782 if ( !ignoreFile
.IsEmpty() )
783 docman
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
785 docman
.DumpDifferences(ctxTop
);
791 // -----------------------------------------------------------------------------
792 // HelpGenVisitor implementation
793 // -----------------------------------------------------------------------------
795 HelpGenVisitor::HelpGenVisitor(const wxString
& directoryOut
,
797 : m_directoryOut(directoryOut
)
799 m_overwrite
= overwrite
;
804 void HelpGenVisitor::Reset()
808 m_inMethodSection
= false;
813 m_textStoredTypedefs
=
814 m_textStoredFunctionComment
= "";
816 m_arrayFuncDocs
.Empty();
818 m_storedEnums
.Empty();
819 m_storedEnumsVerb
.Empty();
823 void HelpGenVisitor::InsertTypedefDocs()
825 m_file
.WriteTeX(m_textStoredTypedefs
);
826 m_textStoredTypedefs
.Empty();
829 void HelpGenVisitor::InsertEnumDocs()
831 size_t count
= m_storedEnums
.GetCount();
832 for ( size_t n
= 0; n
< count
; n
++ )
834 m_file
.WriteTeX(m_storedEnums
[n
]);
835 m_file
.WriteVerbatim(m_storedEnumsVerb
[n
] + '\n');
838 m_storedEnums
.Empty();
839 m_storedEnumsVerb
.Empty();
842 void HelpGenVisitor::InsertDataStructuresHeader()
844 if ( !m_inTypesSection
) {
845 m_inTypesSection
= true;
847 m_file
.WriteVerbatim("\\wxheading{Data structures}\n\n");
851 void HelpGenVisitor::InsertMethodsHeader()
853 if ( !m_inMethodSection
) {
854 m_inMethodSection
= true;
856 m_file
.WriteVerbatim( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
860 void HelpGenVisitor::CloseFunction()
862 if ( !m_funcName
.empty() ) {
863 if ( m_isFirstParam
) {
865 m_textFunc
<< "\\void";
868 m_textFunc
<< "}\n\n";
870 if ( !m_textStoredFunctionComment
.IsEmpty() ) {
871 m_textFunc
<< m_textStoredFunctionComment
<< '\n';
874 m_arrayFuncDocs
.Add(new FunctionDocEntry(m_funcName
, m_textFunc
));
880 void HelpGenVisitor::CloseClass()
886 size_t count
= m_arrayFuncDocs
.GetCount();
890 FunctionDocEntry::classname
= m_classname
;
892 m_arrayFuncDocs
.Sort(FunctionDocEntry::Compare
);
894 // Now examine each first line and if it's been seen, cut it
895 // off (it's a duplicate \membersection)
896 wxHashTable
membersections(wxKEY_STRING
);
898 for ( n
= 0; n
< count
; n
++ )
900 wxString
section(m_arrayFuncDocs
[n
].text
);
902 // Strip leading whitespace
903 int pos
= section
.Find("\\membersection");
906 section
= section
.Mid(pos
);
909 wxString
ms(section
.BeforeFirst(wxT('\n')));
910 if (membersections
.Get(ms
))
912 m_arrayFuncDocs
[n
].text
= section
.AfterFirst(wxT('\n'));
916 membersections
.Put(ms
, & membersections
);
920 for ( n
= 0; n
< count
; n
++ ) {
921 m_file
.WriteTeX(m_arrayFuncDocs
[n
].text
);
924 m_arrayFuncDocs
.Empty();
933 void HelpGenVisitor::EndVisit()
939 m_fileHeader
.Empty();
942 if (m_file
.IsOpened())
948 wxLogVerbose("%s: finished generating for the current file.",
949 GetCurrentTimeFormatted("%H:%M:%S"));
952 void HelpGenVisitor::VisitFile( spFile
& file
)
954 m_fileHeader
= file
.mFileName
;
955 wxLogVerbose("%s: started generating docs for classes from file '%s'...",
956 GetCurrentTimeFormatted("%H:%M:%S"), m_fileHeader
.c_str());
959 void HelpGenVisitor::VisitClass( spClass
& cl
)
963 if (m_file
.IsOpened())
969 wxString name
= cl
.GetName();
971 if ( m_ignoreNames
.IgnoreClass(name
) ) {
972 wxLogVerbose("Skipping ignored class '%s'.", name
.c_str());
977 // the file name is built from the class name by removing the leading "wx"
978 // if any and converting it to the lower case
980 if ( name(0, 2) == "wx" ) {
981 filename
<< name
.c_str() + 2;
987 filename
.MakeLower();
989 filename
.Prepend(m_directoryOut
);
991 if ( !m_overwrite
&& wxFile::Exists(filename
) ) {
992 wxLogError("Won't overwrite existing file '%s' - please use '-f'.",
998 m_inClass
= m_file
.Open(filename
, wxFile::write
);
1000 wxLogError("Can't generate documentation for the class '%s'.",
1007 m_inTypesSection
= false;
1009 wxLogInfo("Created new file '%s' for class '%s'.",
1010 filename
.c_str(), name
.c_str());
1012 // write out the header
1014 header
.Printf("%%\n"
1015 "%% automatically generated by HelpGen %s from\n"
1020 "\\section{\\class{%s}}\\label{%s}\n\n",
1021 GetVersionString().c_str(),
1022 m_fileHeader
.c_str(),
1023 GetCurrentTimeFormatted("%d/%b/%y %H:%M:%S"),
1025 wxString(name
).MakeLower().c_str());
1027 m_file
.WriteVerbatim(header
);
1029 // the entire text we're writing to file
1032 // if the header includes other headers they must be related to it... try to
1033 // automatically generate the "See also" clause
1034 if ( !m_headers
.IsEmpty() ) {
1035 // correspondence between wxWidgets headers and class names
1036 static const char *headers
[] = {
1045 // NULL here means not to insert anything in "See also" for the
1046 // corresponding header
1047 static const char *classes
[] = {
1056 wxASSERT_MSG( WXSIZEOF(headers
) == WXSIZEOF(classes
),
1057 "arrays must be in sync!" );
1059 wxArrayInt interestingClasses
;
1061 size_t count
= m_headers
.Count(), index
;
1062 for ( size_t n
= 0; n
< count
; n
++ ) {
1063 wxString baseHeaderName
= m_headers
[n
].Before('.');
1064 if ( baseHeaderName(0, 3) != "wx/" )
1067 baseHeaderName
.erase(0, 3);
1068 for ( index
= 0; index
< WXSIZEOF(headers
); index
++ ) {
1069 if ( Stricmp(baseHeaderName
, headers
[index
]) == 0 )
1073 if ( (index
< WXSIZEOF(headers
)) && classes
[index
] ) {
1074 // interesting header
1075 interestingClasses
.Add(index
);
1079 if ( !interestingClasses
.IsEmpty() ) {
1080 // do generate "See also" clause
1081 totalText
<< "\\wxheading{See also:}\n\n";
1083 count
= interestingClasses
.Count();
1084 for ( index
= 0; index
< count
; index
++ ) {
1088 totalText
<< MakeHelpref(classes
[interestingClasses
[index
]]);
1091 totalText
<< "\n\n";
1095 // the comment before the class generally explains what is it for so put it
1096 // in place of the class description
1097 if ( cl
.HasComments() ) {
1098 wxString comment
= GetAllComments(cl
);
1100 totalText
<< '\n' << comment
<< '\n';
1103 // derived from section
1104 wxString derived
= "\\wxheading{Derived from}\n\n";
1106 const StrListT
& baseClasses
= cl
.mSuperClassNames
;
1107 if ( baseClasses
.size() == 0 ) {
1108 derived
<< "No base class";
1112 for ( StrListT::const_iterator i
= baseClasses
.begin();
1113 i
!= baseClasses
.end();
1116 // separate from the previous one
1117 derived
<< "\\\\\n";
1123 wxString baseclass
= *i
;
1124 derived
<< "\\helpref{" << baseclass
<< "}";
1125 derived
<< "{" << baseclass
.MakeLower() << "}";
1128 totalText
<< derived
<< "\n\n";
1130 // include file section
1131 wxString includeFile
= "\\wxheading{Include files}\n\n";
1132 includeFile
<< "<" << m_fileHeader
<< ">";
1134 totalText
<< includeFile
<< "\n\n";
1136 // write all this to file
1137 m_file
.WriteTeX(totalText
);
1139 // if there were any enums/typedefs before, insert their documentation now
1140 InsertDataStructuresHeader();
1141 InsertTypedefDocs();
1147 void HelpGenVisitor::VisitEnumeration( spEnumeration
& en
)
1151 if ( m_inMethodSection
) {
1152 // FIXME that's a bug, but tell the user aboit it nevertheless... we
1153 // should be smart enough to process even the enums which come after the
1155 wxLogWarning("enum '%s' ignored, please put it before the class "
1156 "methods.", en
.GetName().c_str());
1160 // simply copy the enum text in the docs
1161 wxString enumeration
= GetAllComments(en
),
1164 enumerationVerb
<< "\\begin{verbatim}\n"
1166 << "\n\\end{verbatim}\n";
1168 // remember for later use if we're not inside a class yet
1170 m_storedEnums
.Add(enumeration
);
1171 m_storedEnumsVerb
.Add(enumerationVerb
);
1174 // write the header for this section if not done yet
1175 InsertDataStructuresHeader();
1177 m_file
.WriteTeX(enumeration
);
1178 m_file
.WriteVerbatim(enumerationVerb
);
1179 m_file
.WriteVerbatim('\n');
1183 void HelpGenVisitor::VisitTypeDef( spTypeDef
& td
)
1187 if ( m_inMethodSection
) {
1188 // FIXME that's a bug, but tell the user aboit it nevertheless...
1189 wxLogWarning("typedef '%s' ignored, please put it before the class "
1190 "methods.", td
.GetName().c_str());
1194 wxString typedefdoc
;
1195 typedefdoc
<< "{\\small \\begin{verbatim}\n"
1196 << "typedef " << td
.mOriginalType
<< ' ' << td
.GetName()
1197 << "\n\\end{verbatim}}\n"
1198 << GetAllComments(td
);
1200 // remember for later use if we're not inside a class yet
1202 if ( !m_textStoredTypedefs
.IsEmpty() ) {
1203 m_textStoredTypedefs
<< '\n';
1206 m_textStoredTypedefs
<< typedefdoc
;
1209 // write the header for this section if not done yet
1210 InsertDataStructuresHeader();
1213 m_file
.WriteTeX(typedefdoc
);
1217 void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine
& pd
)
1219 switch ( pd
.GetStatementType() ) {
1220 case SP_PREP_DEF_INCLUDE_FILE
:
1221 m_headers
.Add(pd
.CPP_GetIncludedFileNeme());
1224 case SP_PREP_DEF_DEFINE_SYMBOL
:
1225 // TODO decide if it's a constant and document it if it is
1230 void HelpGenVisitor::VisitAttribute( spAttribute
& attr
)
1234 // only document the public member variables
1235 if ( !m_inClass
|| !attr
.IsPublic() )
1238 wxLogWarning("Ignoring member variable '%s'.", attr
.GetName().c_str());
1241 void HelpGenVisitor::VisitOperation( spOperation
& op
)
1246 // we don't generate docs right now - either we ignore this class
1247 // entirely or we couldn't open the file
1251 if ( !op
.IsInClass() ) {
1252 // TODO document global functions
1253 wxLogWarning("skipped global function '%s'.", op
.GetName().c_str());
1258 if ( op
.mVisibility
== SP_VIS_PRIVATE
) {
1259 // FIXME should we document protected functions?
1263 m_classname
= op
.GetClass().GetName();
1264 wxString funcname
= op
.GetName();
1266 if ( m_ignoreNames
.IgnoreMethod(m_classname
, funcname
) ) {
1267 wxLogVerbose("Skipping ignored '%s::%s'.",
1268 m_classname
.c_str(), funcname
.c_str());
1273 InsertMethodsHeader();
1276 m_funcName
= funcname
;
1277 m_isFirstParam
= true;
1279 m_textStoredFunctionComment
= GetAllComments(op
);
1281 // start function documentation
1284 // check for the special case of dtor
1286 if ( (funcname
[0u] == '~') && (m_classname
== funcname
.c_str() + 1) ) {
1287 dtor
.Printf("\\destruct{%s}", m_classname
.c_str());
1291 m_textFunc
.Printf("\n"
1292 "\\membersection{%s::%s}\\label{%s}\n",
1293 m_classname
.c_str(), funcname
.c_str(),
1294 MakeLabel(m_classname
, funcname
).c_str());
1298 "\\%sfunc{%s%s}{%s}{",
1299 op
.mIsConstant
? "const" : "",
1300 op
.mIsVirtual
? "virtual " : "",
1301 op
.mRetType
.c_str(),
1306 void HelpGenVisitor::VisitParameter( spParameter
& param
)
1308 if ( m_funcName
.empty() )
1311 if ( m_isFirstParam
) {
1312 m_isFirstParam
= false;
1318 m_textFunc
<< "\\param{" << param
.mType
<< " }{" << param
.GetName();
1319 wxString defvalue
= param
.mInitVal
;
1320 if ( !defvalue
.IsEmpty() ) {
1321 m_textFunc
<< " = " << defvalue
;
1327 // ---------------------------------------------------------------------------
1329 // ---------------------------------------------------------------------------
1331 DocManager::DocManager(bool checkParamNames
)
1333 m_checkParamNames
= checkParamNames
;
1336 size_t DocManager::TryMatch(const char *str
, const char *match
)
1338 size_t lenMatch
= 0;
1339 while ( str
[lenMatch
] == match
[lenMatch
] ) {
1342 if ( match
[lenMatch
] == '\0' )
1349 bool DocManager::SkipUntil(const char **pp
, char c
)
1351 const char *p
= *pp
;
1367 bool DocManager::SkipSpaceUntil(const char **pp
, char c
)
1369 const char *p
= *pp
;
1371 if ( !isspace(*p
) || *p
== '\0' )
1385 wxString
DocManager::ExtractStringBetweenBraces(const char **pp
)
1389 if ( !SkipSpaceUntil(pp
, '{') ) {
1390 wxLogWarning("file %s(%d): '{' expected after '\\param'",
1391 m_filename
.c_str(), m_line
);
1395 const char *startParam
= ++*pp
; // skip '{'
1397 if ( !SkipUntil(pp
, '}') ) {
1398 wxLogWarning("file %s(%d): '}' expected after '\\param'",
1399 m_filename
.c_str(), m_line
);
1402 result
= wxString(startParam
, (*pp
)++ - startParam
);
1409 bool DocManager::ParseTeXFile(const wxString
& filename
)
1411 m_filename
= filename
;
1413 wxFile
file(m_filename
, wxFile::read
);
1414 if ( !file
.IsOpened() )
1417 off_t len
= file
.Length();
1418 if ( len
== wxInvalidOffset
)
1421 char *buf
= new char[len
+ 1];
1424 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1430 // reinit everything
1433 wxLogVerbose("%s: starting to parse doc file '%s'.",
1434 GetCurrentTimeFormatted("%H:%M:%S"), m_filename
.c_str());
1436 // the name of the class from the last "\membersection" command: we assume
1437 // that the following "\func" or "\constfunc" always documents a method of
1438 // this class (and it should always be like that in wxWidgets documentation)
1441 for ( const char *current
= buf
; current
- buf
< len
; current
++ ) {
1442 // FIXME parsing is awfully inefficient
1444 if ( *current
== '%' ) {
1445 // comment, skip until the end of line
1447 SkipUntil(¤t
, '\n');
1452 // all the command we're interested in start with '\\'
1453 while ( *current
!= '\\' && *current
!= '\0' ) {
1454 if ( *current
++ == '\n' )
1458 if ( *current
== '\0' ) {
1459 // no more TeX commands left
1463 current
++; // skip '\\'
1471 } foundCommand
= Nothing
;
1473 size_t lenMatch
= TryMatch(current
, "func");
1475 foundCommand
= Func
;
1478 lenMatch
= TryMatch(current
, "constfunc");
1480 foundCommand
= ConstFunc
;
1482 lenMatch
= TryMatch(current
, "membersection");
1485 foundCommand
= MemberSect
;
1489 if ( foundCommand
== Nothing
)
1492 current
+= lenMatch
;
1494 if ( !SkipSpaceUntil(¤t
, '{') ) {
1495 wxLogWarning("file %s(%d): '{' expected after \\func, "
1496 "\\constfunc or \\membersection.",
1497 m_filename
.c_str(), m_line
);
1504 if ( foundCommand
== MemberSect
) {
1505 // what follows has the form <classname>::<funcname>
1506 const char *startClass
= current
;
1507 if ( !SkipUntil(¤t
, ':') || *(current
+ 1) != ':' ) {
1508 wxLogWarning("file %s(%d): '::' expected after "
1509 "\\membersection.", m_filename
.c_str(), m_line
);
1512 classname
= wxString(startClass
, current
- startClass
);
1513 TeXUnfilter(&classname
);
1519 // extract the return type
1520 const char *startRetType
= current
;
1522 if ( !SkipUntil(¤t
, '}') ) {
1523 wxLogWarning("file %s(%d): '}' expected after return type",
1524 m_filename
.c_str(), m_line
);
1529 wxString returnType
= wxString(startRetType
, current
- startRetType
);
1530 TeXUnfilter(&returnType
);
1533 if ( !SkipSpaceUntil(¤t
, '{') ) {
1534 wxLogWarning("file %s(%d): '{' expected after return type",
1535 m_filename
.c_str(), m_line
);
1541 const char *funcEnd
= current
;
1542 if ( !SkipUntil(&funcEnd
, '}') ) {
1543 wxLogWarning("file %s(%d): '}' expected after function name",
1544 m_filename
.c_str(), m_line
);
1549 wxString funcName
= wxString(current
, funcEnd
- current
);
1550 current
= funcEnd
+ 1;
1552 // trim spaces from both sides
1553 funcName
.Trim(false);
1554 funcName
.Trim(true);
1556 // special cases: '$...$' may be used for LaTeX inline math, remove the
1558 if ( funcName
.Find('$') != wxNOT_FOUND
) {
1560 for ( const char *p
= funcName
.c_str(); *p
!= '\0'; p
++ ) {
1561 if ( *p
!= '$' && !isspace(*p
) )
1568 // \destruct{foo} is really ~foo
1569 if ( funcName
[0u] == '\\' ) {
1570 size_t len
= strlen("\\destruct{");
1571 if ( funcName(0, len
) != "\\destruct{" ) {
1572 wxLogWarning("file %s(%d): \\destruct expected",
1573 m_filename
.c_str(), m_line
);
1578 funcName
.erase(0, len
);
1579 funcName
.Prepend('~');
1581 if ( !SkipSpaceUntil(¤t
, '}') ) {
1582 wxLogWarning("file %s(%d): '}' expected after destructor",
1583 m_filename
.c_str(), m_line
);
1588 funcEnd
++; // there is an extra '}' to count
1591 TeXUnfilter(&funcName
);
1594 current
= funcEnd
+ 1; // skip '}'
1595 if ( !SkipSpaceUntil(¤t
, '{') ||
1596 (current
++, !SkipSpaceUntil(¤t
, '\\')) ) {
1597 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1598 m_filename
.c_str(), m_line
);
1603 wxArrayString paramNames
, paramTypes
, paramValues
;
1605 bool isVararg
= false;
1607 current
++; // skip '\\'
1608 lenMatch
= TryMatch(current
, "void");
1610 lenMatch
= TryMatch(current
, "param");
1611 while ( lenMatch
&& (current
- buf
< len
) ) {
1612 current
+= lenMatch
;
1614 // now come {paramtype}{paramname}
1615 wxString paramType
= ExtractStringBetweenBraces(¤t
);
1616 if ( !!paramType
) {
1617 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1618 if ( !!paramText
) {
1619 // the param declaration may contain default value
1620 wxString paramName
= paramText
.BeforeFirst('='),
1621 paramValue
= paramText
.AfterFirst('=');
1623 // sanitize all strings
1624 TeXUnfilter(¶mValue
);
1625 TeXUnfilter(¶mName
);
1626 TeXUnfilter(¶mType
);
1628 paramValues
.Add(paramValue
);
1629 paramNames
.Add(paramName
);
1630 paramTypes
.Add(paramType
);
1635 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1636 if ( paramText
== "..." ) {
1640 wxLogWarning("Parameters of '%s::%s' are in "
1642 classname
.c_str(), funcName
.c_str());
1647 current
= SkipSpaces(current
);
1648 if ( *current
== ',' || *current
== '}' ) {
1649 current
= SkipSpaces(++current
);
1651 lenMatch
= TryMatch(current
, "\\param");
1654 wxLogWarning("file %s(%d): ',' or '}' expected after "
1655 "'\\param'", m_filename
.c_str(), m_line
);
1661 // if we got here there was no '\\void', so must have some params
1662 if ( paramNames
.IsEmpty() ) {
1663 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1664 m_filename
.c_str(), m_line
);
1670 // verbose diagnostic output
1672 size_t param
, paramCount
= paramNames
.GetCount();
1673 for ( param
= 0; param
< paramCount
; param
++ ) {
1678 paramsAll
<< paramTypes
[param
] << ' ' << paramNames
[param
];
1681 wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
1682 m_filename
.c_str(), m_line
,
1687 foundCommand
== ConstFunc
? " const" : "");
1689 // store the info about the just found function
1690 ArrayMethodInfo
*methods
;
1691 int index
= m_classes
.Index(classname
);
1692 if ( index
== wxNOT_FOUND
) {
1693 m_classes
.Add(classname
);
1695 methods
= new ArrayMethodInfo
;
1696 m_methods
.Add(methods
);
1699 methods
= m_methods
[(size_t)index
];
1702 ArrayParamInfo params
;
1703 for ( param
= 0; param
< paramCount
; param
++ ) {
1704 params
.Add(new ParamInfo(paramTypes
[param
],
1706 paramValues
[param
]));
1709 MethodInfo
*method
= new MethodInfo(returnType
, funcName
, params
);
1710 if ( foundCommand
== ConstFunc
)
1711 method
->SetFlag(MethodInfo::Const
);
1713 method
->SetFlag(MethodInfo::Vararg
);
1715 methods
->Add(method
);
1720 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1721 GetCurrentTimeFormatted("%H:%M:%S"), m_filename
.c_str());
1726 bool DocManager::DumpDifferences(spContext
*ctxTop
) const
1728 typedef MMemberListT::const_iterator MemberIndex
;
1730 bool foundDiff
= false;
1732 // flag telling us whether the given class was found at all in the header
1733 size_t nClass
, countClassesInDocs
= m_classes
.GetCount();
1734 bool *classExists
= new bool[countClassesInDocs
];
1735 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1736 classExists
[nClass
] = false;
1739 // ctxTop is normally an spFile
1740 wxASSERT( ctxTop
->GetContextType() == SP_CTX_FILE
);
1742 const MMemberListT
& classes
= ctxTop
->GetMembers();
1743 for ( MemberIndex i
= classes
.begin(); i
!= classes
.end(); i
++ ) {
1744 spContext
*ctx
= *i
;
1745 if ( ctx
->GetContextType() != SP_CTX_CLASS
) {
1746 // TODO process also global functions, macros, ...
1750 spClass
*ctxClass
= (spClass
*)ctx
;
1751 const wxString
& nameClass
= ctxClass
->mName
;
1752 int index
= m_classes
.Index(nameClass
);
1753 if ( index
== wxNOT_FOUND
) {
1754 if ( !m_ignoreNames
.IgnoreClass(nameClass
) ) {
1757 wxLogError("Class '%s' is not documented at all.",
1761 // it makes no sense to check for its functions
1765 classExists
[index
] = true;
1768 // array of method descriptions for this class
1769 const ArrayMethodInfo
& methods
= *(m_methods
[index
]);
1770 size_t nMethod
, countMethods
= methods
.GetCount();
1772 // flags telling if we already processed given function
1773 bool *methodExists
= new bool[countMethods
];
1774 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1775 methodExists
[nMethod
] = false;
1778 wxArrayString aOverloadedMethods
;
1780 const MMemberListT
& functions
= ctxClass
->GetMembers();
1781 for ( MemberIndex j
= functions
.begin(); j
!= functions
.end(); j
++ ) {
1783 if ( ctx
->GetContextType() != SP_CTX_OPERATION
)
1786 spOperation
*ctxMethod
= (spOperation
*)ctx
;
1787 const wxString
& nameMethod
= ctxMethod
->mName
;
1789 // find all functions with the same name
1790 wxArrayInt aMethodsWithSameName
;
1791 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1792 if ( methods
[nMethod
]->GetName() == nameMethod
)
1793 aMethodsWithSameName
.Add(nMethod
);
1796 if ( aMethodsWithSameName
.IsEmpty() && ctxMethod
->IsPublic() ) {
1797 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1800 wxLogError("'%s::%s' is not documented.",
1802 nameMethod
.c_str());
1805 // don't check params
1808 else if ( aMethodsWithSameName
.GetCount() == 1 ) {
1809 index
= (size_t)aMethodsWithSameName
[0u];
1810 methodExists
[index
] = true;
1812 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1815 if ( !ctxMethod
->IsPublic() ) {
1816 wxLogWarning("'%s::%s' is documented but not public.",
1818 nameMethod
.c_str());
1821 // check that the flags match
1822 const MethodInfo
& method
= *(methods
[index
]);
1824 bool isVirtual
= ctxMethod
->mIsVirtual
;
1825 if ( isVirtual
!= method
.HasFlag(MethodInfo::Virtual
) ) {
1826 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1830 isVirtual
? "not " : "");
1833 bool isConst
= ctxMethod
->mIsConstant
;
1834 if ( isConst
!= method
.HasFlag(MethodInfo::Const
) ) {
1835 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1839 isConst
? "not " : "");
1842 // check that the params match
1843 const MMemberListT
& params
= ctxMethod
->GetMembers();
1845 if ( params
.size() != method
.GetParamCount() ) {
1846 wxLogError("Incorrect number of parameters for '%s::%s' "
1847 "in the docs: should be %d instead of %d.",
1850 params
.size(), method
.GetParamCount());
1854 for ( MemberIndex k
= params
.begin();
1859 // what else can a function have?
1860 wxASSERT( ctx
->GetContextType() == SP_CTX_PARAMETER
);
1862 spParameter
*ctxParam
= (spParameter
*)ctx
;
1863 const ParamInfo
& param
= method
.GetParam(nParam
);
1864 if ( m_checkParamNames
&&
1865 (param
.GetName() != ctxParam
->mName
) ) {
1868 wxLogError("Parameter #%d of '%s::%s' should be "
1869 "'%s' and not '%s'.",
1873 ctxParam
->mName
.c_str(),
1874 param
.GetName().c_str());
1879 if ( param
.GetType() != ctxParam
->mType
) {
1882 wxLogError("Type of parameter '%s' of '%s::%s' "
1883 "should be '%s' and not '%s'.",
1884 ctxParam
->mName
.c_str(),
1887 ctxParam
->mType
.c_str(),
1888 param
.GetType().GetName().c_str());
1893 if ( param
.GetDefValue() != ctxParam
->mInitVal
) {
1894 wxLogWarning("Default value of parameter '%s' of "
1895 "'%s::%s' should be '%s' and not "
1897 ctxParam
->mName
.c_str(),
1900 ctxParam
->mInitVal
.c_str(),
1901 param
.GetDefValue().c_str());
1907 // TODO OVER add real support for overloaded methods
1909 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1912 if ( aOverloadedMethods
.Index(nameMethod
) == wxNOT_FOUND
) {
1913 // mark all methods with this name as existing
1914 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1915 if ( methods
[nMethod
]->GetName() == nameMethod
)
1916 methodExists
[nMethod
] = true;
1919 aOverloadedMethods
.Add(nameMethod
);
1921 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1922 "stupid to find the right match - skipping "
1923 "the param and flags checks.",
1925 nameMethod
.c_str());
1927 //else: warning already given
1931 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1932 if ( !methodExists
[nMethod
] ) {
1933 const wxString
& nameMethod
= methods
[nMethod
]->GetName();
1934 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1937 wxLogError("'%s::%s' is documented but doesn't exist.",
1939 nameMethod
.c_str());
1944 delete [] methodExists
;
1947 // check that all classes we found in the docs really exist
1948 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1949 if ( !classExists
[nClass
] ) {
1952 wxLogError("Class '%s' is documented but doesn't exist.",
1953 m_classes
[nClass
].c_str());
1957 delete [] classExists
;
1962 DocManager::~DocManager()
1964 WX_CLEAR_ARRAY(m_methods
);
1967 // ---------------------------------------------------------------------------
1968 // IgnoreNamesHandler implementation
1969 // ---------------------------------------------------------------------------
1971 int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry
*first
,
1972 IgnoreListEntry
*second
)
1974 // first compare the classes
1975 int rc
= first
->m_classname
.Cmp(second
->m_classname
);
1977 rc
= first
->m_funcname
.Cmp(second
->m_funcname
);
1982 bool IgnoreNamesHandler::AddNamesFromFile(const wxString
& filename
)
1984 wxFile
file(filename
, wxFile::read
);
1985 if ( !file
.IsOpened() )
1988 off_t len
= file
.Length();
1989 if ( len
== wxInvalidOffset
)
1992 char *buf
= new char[len
+ 1];
1995 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
2002 for ( const char *current
= buf
; ; current
++ ) {
2004 // skip DOS line separator
2005 if ( *current
== '\r' )
2009 if ( *current
== '\n' || *current
== '\0' ) {
2010 if ( line
[0u] != '#' ) {
2011 if ( line
.Find(':') != wxNOT_FOUND
) {
2012 wxString classname
= line
.BeforeFirst(':'),
2013 funcname
= line
.AfterLast(':');
2014 m_ignore
.Add(new IgnoreListEntry(classname
, funcname
));
2018 m_ignore
.Add(new IgnoreListEntry(line
, ""));
2023 if ( *current
== '\0' )
2038 // -----------------------------------------------------------------------------
2039 // global function implementation
2040 // -----------------------------------------------------------------------------
2042 static wxString
MakeLabel(const char *classname
, const char *funcname
)
2044 wxString
label(classname
);
2045 if ( funcname
&& funcname
[0] == '\\' ) {
2046 // we may have some special TeX macro - so far only \destruct exists,
2047 // but may be later others will be added
2048 static const char *macros
[] = { "destruct" };
2049 static const char *replacement
[] = { "dtor" };
2052 for ( n
= 0; n
< WXSIZEOF(macros
); n
++ ) {
2053 if ( strncmp(funcname
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) {
2059 if ( n
== WXSIZEOF(macros
) ) {
2060 wxLogWarning("unknown function name '%s' - leaving as is.",
2064 funcname
= replacement
[n
];
2069 // special treatment for operatorXXX() stuff because the C operators
2070 // are not valid in LaTeX labels
2072 if ( wxString(funcname
).StartsWith("operator", &oper
) ) {
2073 label
<< "operator";
2086 for ( n
= 0; n
< WXSIZEOF(operatorNames
); n
++ ) {
2087 if ( oper
== operatorNames
[n
].oper
) {
2088 label
<< operatorNames
[n
].name
;
2094 if ( n
== WXSIZEOF(operatorNames
) ) {
2095 wxLogWarning("unknown operator '%s' - making dummy label.",
2101 else // simply use the func name
2112 static wxString
MakeHelpref(const char *argument
)
2115 helpref
<< "\\helpref{" << argument
<< "}{" << MakeLabel(argument
) << '}';
2120 static void TeXFilter(wxString
* str
)
2122 // TeX special which can be quoted (don't include backslash nor braces as
2124 static wxRegEx
reNonSpecialSpecials("[#$%&_]"),
2128 reNonSpecialSpecials
.ReplaceAll(str
, "\\\\\\0");
2130 // can't quote these ones as they produce accents when preceded by
2131 // backslash, so put them inside verb
2132 reAccents
.ReplaceAll(str
, "\\\\verb|\\0|");
2135 static void TeXUnfilter(wxString
* str
)
2137 // FIXME may be done much more quickly
2142 static wxRegEx
reNonSpecialSpecials("\\\\([#$%&_{}])"),
2143 reAccents("\\\\verb\\|([~^])\\|");
2145 reNonSpecialSpecials
.ReplaceAll(str
, "\\1");
2146 reAccents
.ReplaceAll(str
, "\\1");
2149 static wxString
GetAllComments(const spContext
& ctx
)
2152 const MCommentListT
& commentsList
= ctx
.GetCommentList();
2153 for ( MCommentListT::const_iterator i
= commentsList
.begin();
2154 i
!= commentsList
.end();
2156 wxString comment
= (*i
)->GetText();
2158 // don't take comments like "// ----------" &c
2159 comment
.Trim(false);
2161 comment
== wxString(comment
[0u], comment
.length() - 1) + '\n' )
2164 comments
<< comment
;
2170 static const char *GetCurrentTimeFormatted(const char *timeFormat
)
2172 static char s_timeBuffer
[128];
2177 ptmNow
= localtime(&timeNow
);
2179 strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
);
2181 return s_timeBuffer
;
2184 static const wxString
GetVersionString()
2186 wxString version
= "$Revision$";
2187 wxRegEx("^\\$Revision$$").ReplaceFirst(&version
, "\\1");
2193 Revision 1.35 2004/12/12 11:03:31 VZ
2194 give an error message if we're built in Unicode mode (in response to bug 1079224)
2196 Revision 1.34 2004/11/23 09:53:31 JS
2197 Changed GPL to wxWindows Licence
2199 Revision 1.33 2004/11/12 03:30:07 RL
2201 Cruft cleanup from MJW, strip the tabs out of sound.cpp
2203 Revision 1.32 2004/11/10 21:02:58 VZ
2204 new set of fixes for problems due to huge files support: drop wxFileSize_t, use wxFileOffset only, make wxInvalidOffset an int (main part of the patch 1063498)
2206 Revision 1.31 2004/10/05 15:38:29 ABX
2207 Warning fixes found under hardest mode of OpenWatcom. Seems clean in Borland, MinGW and DMC.
2209 Revision 1.30 2004/06/18 19:25:50 ABX
2210 Small step in making HelpGen up to date unicode application.
2212 Revision 1.29 2004/06/17 19:00:22 ABX
2213 Warning fixes. Code cleanup. Whitespaces and tabs removed.
2215 Revision 1.28 2004/05/25 11:19:57 JS
2218 Revision 1.27 2003/10/13 17:21:30 MBN
2221 Revision 1.26 2003/09/29 15:18:35 MBN
2222 (Blind) compilation fix for Sun compiler.
2224 Revision 1.25 2003/09/03 17:39:27 MBN
2227 Revision 1.24 2003/08/13 22:59:37 VZ
2230 Revision 1.23 2003/06/13 17:05:43 VZ
2231 quote '|' inside regexes (fixes dump mode); fixed crash due to strange HelpGenApp code
2233 Revision 1.22 2002/01/21 21:18:50 JS
2234 Now adds 'include file' heading
2236 Revision 1.21 2002/01/04 11:06:09 JS
2237 Fixed missing membersections bug and also bug with functions not being written
2240 Revision 1.20 2002/01/03 14:23:33 JS
2241 Added code to make it not duplicate membersections for overloaded functions
2243 Revision 1.19 2002/01/03 13:34:12 JS
2244 Added FlushAll to CloseClass, otherwise text was only flushed right at the end,
2245 and appeared in one file.
2247 Revision 1.18 2002/01/03 12:02:47 JS
2248 Added main() and corrected VC++ project settings
2250 Revision 1.17 2001/11/30 21:43:35 VZ
2251 now the methods are sorted in the correct order in the generated docs
2253 Revision 1.16 2001/11/28 19:27:33 VZ
2254 HelpGen doesn't work in GUI mode
2256 Revision 1.15 2001/11/22 21:59:58 GD
2257 use "..." instead of <...> for wx headers
2259 Revision 1.14 2001/07/19 13:51:29 VZ
2260 fixes to version string
2262 Revision 1.13 2001/07/19 13:44:57 VZ
2263 1. compilation fixes
2264 2. don't quote special characters inside verbatim environment
2266 Revision 1.12 2000/10/09 13:53:33 juliansmart
2268 Doc corrections; added HelpGen project files
2270 Revision 1.11 2000/07/15 19:50:42 cvsuser
2273 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
2274 don't trasnform output dir name to lower case
2276 Revision 1.10 2000/03/11 10:05:23 VS
2277 now compiles with wxBase
2279 Revision 1.9 2000/01/16 13:25:21 VS
2280 compilation fixes (gcc)
2282 Revision 1.8 1999/09/13 14:29:39 JS
2284 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2285 into src for simplicity; added VC++ 5 project file
2287 Revision 1.7 1999/02/21 22:32:32 VZ
2288 1. more C++ parser fixes - now it almost parses wx/string.h
2289 a) #if/#ifdef/#else (very) limited support
2290 b) param type fix - now indirection chars are correctly handled
2291 c) class/struct/union distinction
2292 d) public/private fixes
2293 e) Dump() function added - very useful for debugging
2295 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2296 by default, and this option switches it on)
2298 Revision 1.6 1999/02/20 23:00:26 VZ
2299 1. new 'diff' mode which seems to work
2300 2. output files are not overwritten in 'dmup' mode
2301 3. fixes for better handling of const functions and operators
2302 ----------------------------
2304 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2305 1. Parser improvements
2306 a) const and virtual methods are parsed correctly (not static yet)
2307 b) "const" which is part of the return type is not swallowed
2309 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2310 "//---------" kind comments discarded now.
2311 ----------------------------
2313 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2315 some tweaks to HelpGen
2316 ----------------------------
2318 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2320 HelpGen starting to compile with VC++
2321 ----------------------------
2323 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2325 supports typedefs, generates "See also:" and adds "virtual " for virtual
2327 ----------------------------
2329 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2331 HelpGen is a prototype of the tool for automatic generation of the .tex files
2332 for wxWidgets documentation from C++ headers
2335 /* vi: set tw=80 et ts=4 sw=4: */