1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Main program file for HelpGen
4 // Author: Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Copyright: (c) 1999 VZ
10 /////////////////////////////////////////////////////////////////////////////
15 1. wx/string.h confuses C++ parser terribly
16 2. C++ parser doesn't know about virtual functions, nor static ones
17 3. param checking is not done for vararg functions
18 4. type comparison is dumb: it doesn't know that "char *" is the same
19 that "char []" nor that "const char *" is the same as "char const *"
21 TODO (+ means fixed), see also the change log at the end of the file.
23 (i) small fixes in the current version
25 +1. Quote special TeX characters like '&' and '_' (=> derive from wxFile)
27 3. Document global variables
30 6. Include file name/line number in the "diff" messages?
31 +7. Support for vararg functions
33 (ii) plans for version 2
34 1. Use wxTextFile for direct file access to avoid one scan method problems
35 2. Use command line parser class for the options
36 3. support for overloaded functions in diff mode (search for OVER)
38 (iii) plans for version 3
39 1. Merging with existing files
43 // =============================================================================
45 // =============================================================================
47 // -----------------------------------------------------------------------------
49 // -----------------------------------------------------------------------------
52 #include "wx/wxprec.h"
55 #error "This is a console program and can be only compiled using wxBase"
59 #include "wx/string.h"
61 #include "wx/dynarray.h"
68 // C++ parsing classes
75 // argh, Windows defines this
80 // -----------------------------------------------------------------------------
82 // -----------------------------------------------------------------------------
84 class HelpGenApp
: public wxApp
89 // don't let wxWin parse our cmd line, we do it ourselves
90 virtual bool OnInit() { return TRUE
; }
95 // IMPLEMENT_APP(HelpGenApp);
97 // -----------------------------------------------------------------------------
99 // -----------------------------------------------------------------------------
101 // return the label for the given function name (i.e. argument of \label)
102 static wxString
MakeLabel(const char *classname
, const char *funcname
= NULL
);
104 // return the whole \helpref{arg}{arg_label} string
105 static wxString
MakeHelpref(const char *argument
);
107 // [un]quote special TeX characters (in place)
108 static void TeXFilter(wxString
* str
);
109 static void TeXUnfilter(wxString
* str
); // also trims spaces
111 // get all comments associated with this context
112 static wxString
GetAllComments(const spContext
& ctx
);
114 // get the string with current time (returns pointer to static buffer)
115 // timeFormat is used for the call of strftime(3)
116 static const char *GetCurrentTime(const char *timeFormat
);
118 // get the string containing the program version
119 static const wxString
GetVersionString();
121 // -----------------------------------------------------------------------------
123 // -----------------------------------------------------------------------------
125 // a function documentation entry
126 struct FunctionDocEntry
128 FunctionDocEntry(const wxString
& name_
, const wxString
& text_
)
129 : name(name_
), text(text_
) { }
134 // the function doc text
138 static int Compare(FunctionDocEntry
**pp1
, FunctionDocEntry
**pp2
)
140 // the methods should appear in the following order: ctors, dtor, all
141 // the rest in the alphabetical order
142 bool isCtor1
= (*pp1
)->name
== classname
;
143 bool isCtor2
= (*pp2
)->name
== classname
;
147 // we don't order the ctors because we don't know how to do it
151 // ctor comes before non-ctor
156 // non-ctor must come after ctor
160 wxString dtorname
= wxString('~') + classname
;
162 // there is only one dtor, so the logic here is simpler
163 if ( (*pp1
)->name
== dtorname
) {
166 else if ( (*pp2
)->name
== dtorname
) {
170 // two normal methods
171 return strcmp((*pp1
)->name
, (*pp2
)->name
);
175 static wxString classname
;
178 wxString
FunctionDocEntry::classname
;
180 WX_DECLARE_OBJARRAY(FunctionDocEntry
, FunctionDocEntries
);
182 #include "wx/arrimpl.cpp"
184 WX_DEFINE_OBJARRAY(FunctionDocEntries
);
186 // add a function which sanitazes the string before writing it to the file and
187 // also capable of delaying output and sorting it before really writing it to
188 // the file (done from FlushAll())
189 class wxTeXFile
: public wxFile
194 // write a string to file verbatim (should only be used for the strings
195 // inside verbatim environment)
196 void WriteVerbatim(const wxString
& s
)
201 // write a string quoting TeX specials in it
202 void WriteTeX(const wxString
& s
)
210 // do write everything to file
213 if ( m_text
.empty() )
216 if ( !Write(m_text
) ) {
217 wxLogError("Failed to output generated documentation.");
228 wxTeXFile(const wxTeXFile
&);
229 wxTeXFile
& operator=(const wxTeXFile
&);
234 // helper class which manages the classes and function names to ignore for
235 // the documentation purposes (used by both HelpGenVisitor and DocManager)
236 class IgnoreNamesHandler
239 IgnoreNamesHandler() : m_ignore(CompareIgnoreListEntries
) { }
240 ~IgnoreNamesHandler() { WX_CLEAR_ARRAY(m_ignore
); }
242 // load file with classes/functions to ignore (add them to the names we
244 bool AddNamesFromFile(const wxString
& filename
);
246 // return TRUE if we ignore this function
247 bool IgnoreMethod(const wxString
& classname
,
248 const wxString
& funcname
) const
250 if ( IgnoreClass(classname
) )
253 IgnoreListEntry
ignore(classname
, funcname
);
255 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
258 // return TRUE if we ignore this class entirely
259 bool IgnoreClass(const wxString
& classname
) const
261 IgnoreListEntry
ignore(classname
, "");
263 return m_ignore
.Index(&ignore
) != wxNOT_FOUND
;
267 struct IgnoreListEntry
269 IgnoreListEntry(const wxString
& classname
,
270 const wxString
& funcname
)
271 : m_classname(classname
), m_funcname(funcname
)
275 wxString m_classname
;
276 wxString m_funcname
; // if empty, ignore class entirely
279 static int CompareIgnoreListEntries(IgnoreListEntry
*first
,
280 IgnoreListEntry
*second
);
282 // for efficiency, let's sort it
283 WX_DEFINE_SORTED_ARRAY(IgnoreListEntry
*, ArrayNamesToIgnore
);
285 ArrayNamesToIgnore m_ignore
;
288 IgnoreNamesHandler(const IgnoreNamesHandler
&);
289 IgnoreNamesHandler
& operator=(const IgnoreNamesHandler
&);
292 // visitor implementation which writes all collected data to a .tex file
293 class HelpGenVisitor
: public spVisitor
297 HelpGenVisitor(const wxString
& directoryOut
, bool overwrite
);
299 virtual void VisitFile( spFile
& fl
);
300 virtual void VisitClass( spClass
& cl
);
301 virtual void VisitEnumeration( spEnumeration
& en
);
302 virtual void VisitTypeDef( spTypeDef
& td
);
303 virtual void VisitPreprocessorLine( spPreprocessorLine
& pd
);
304 virtual void VisitAttribute( spAttribute
& attr
);
305 virtual void VisitOperation( spOperation
& op
);
306 virtual void VisitParameter( spParameter
& param
);
310 // get our `ignore' object
311 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
313 // shut up g++ warning (ain't it stupid?)
314 virtual ~HelpGenVisitor() { }
317 // (re)initialize the state
320 // insert documentation for enums/typedefs coming immediately before the
321 // class declaration into the class documentation
322 void InsertTypedefDocs();
323 void InsertEnumDocs();
325 // write the headers for corresponding sections (only once)
326 void InsertDataStructuresHeader();
327 void InsertMethodsHeader();
329 // terminate the function documentation if it was started
330 void CloseFunction();
332 // write out all function docs when there are no more left in this class
333 // after sorting them in alphabetical order
336 wxString m_directoryOut
, // directory for the output
337 m_fileHeader
; // name of the .h file we parse
338 bool m_overwrite
; // overwrite existing files?
339 wxTeXFile m_file
; // file we're writing to now
342 bool m_inClass
, // TRUE after file successfully opened
343 m_inTypesSection
, // enums & typedefs go there
344 m_inMethodSection
, // functions go here
345 m_isFirstParam
; // first parameter of current function?
347 // non empty while parsing a class
348 wxString m_classname
;
350 // these are only non-empty while parsing a method:
351 wxString m_funcName
, // the function name
352 m_textFunc
; // the function doc text
354 // the array containing the documentation entries for the functions in the
355 // class currently being parsed
356 FunctionDocEntries m_arrayFuncDocs
;
358 // holders for "saved" documentation
359 wxString m_textStoredTypedefs
,
360 m_textStoredFunctionComment
;
362 // for enums we have to use an array as we can't intermix the normal text
363 // and the text inside verbatim environment
364 wxArrayString m_storedEnums
,
367 // headers included by this file
368 wxArrayString m_headers
;
370 // ignore handler: tells us which classes to ignore for doc generation
372 IgnoreNamesHandler m_ignoreNames
;
375 HelpGenVisitor(const HelpGenVisitor
&);
376 HelpGenVisitor
& operator=(const HelpGenVisitor
&);
379 // documentation manager - a class which parses TeX files and remembers the
380 // functions documented in them and can later compare them with all functions
381 // found under ctxTop by C++ parser
385 DocManager(bool checkParamNames
);
388 // returns FALSE on failure
389 bool ParseTeXFile(const wxString
& filename
);
391 // returns FALSE if there were any differences
392 bool DumpDifferences(spContext
*ctxTop
) const;
394 // get our `ignore' object
395 IgnoreNamesHandler
& GetIgnoreHandler() { return m_ignoreNames
; }
401 // returns the length of 'match' if the string 'str' starts with it or 0
403 static size_t TryMatch(const char *str
, const char *match
);
405 // skip spaces: returns pointer to first non space character (also
406 // updates the value of m_line)
407 const char *SkipSpaces(const char *p
)
409 while ( isspace(*p
) ) {
417 // skips characters until the next 'c' in '*pp' unless it ends before in
418 // which case FALSE is returned and pp points to '\0', otherwise TRUE is
419 // returned and pp points to 'c'
420 bool SkipUntil(const char **pp
, char c
);
422 // the same as SkipUntil() but only spaces are skipped: on first non space
423 // character different from 'c' the function stops and returns FALSE
424 bool SkipSpaceUntil(const char **pp
, char c
);
426 // extract the string between {} and modify '*pp' to point at the
427 // character immediately after the closing '}'. The returned string is empty
429 wxString
ExtractStringBetweenBraces(const char **pp
);
431 // the current file and line while we're in ParseTeXFile (for error
436 // functions and classes to ignore during diff
437 // -------------------------------------------
439 IgnoreNamesHandler m_ignoreNames
;
441 // information about all functions documented in the TeX file(s)
442 // -------------------------------------------------------------
444 // info about a type: for now stored as text string, but must be parsed
445 // further later (to know that "char *" == "char []" - TODO)
449 TypeInfo(const wxString
& type
) : m_type(type
) { }
451 bool operator==(const wxString
& type
) const { return m_type
== type
; }
452 bool operator!=(const wxString
& type
) const { return m_type
!= type
; }
454 const wxString
& GetName() const { return m_type
; }
460 // info abotu a function parameter
464 ParamInfo(const wxString
& type
,
465 const wxString
& name
,
466 const wxString
& value
)
467 : m_type(type
), m_name(name
), m_value(value
)
471 const TypeInfo
& GetType() const { return m_type
; }
472 const wxString
& GetName() const { return m_name
; }
473 const wxString
& GetDefValue() const { return m_value
; }
476 TypeInfo m_type
; // type of parameter
477 wxString m_name
; // name
478 wxString m_value
; // default value
481 WX_DEFINE_ARRAY(ParamInfo
*, ArrayParamInfo
);
483 // info about a function
496 MethodInfo(const wxString
& type
,
497 const wxString
& name
,
498 const ArrayParamInfo
& params
)
499 : m_typeRet(type
), m_name(name
), m_params(params
)
504 void SetFlag(MethodFlags flag
) { m_flags
|= flag
; }
506 const TypeInfo
& GetType() const { return m_typeRet
; }
507 const wxString
& GetName() const { return m_name
; }
508 const ParamInfo
& GetParam(size_t n
) const { return *(m_params
[n
]); }
509 size_t GetParamCount() const { return m_params
.GetCount(); }
511 bool HasFlag(MethodFlags flag
) const { return (m_flags
& flag
) != 0; }
513 ~MethodInfo() { WX_CLEAR_ARRAY(m_params
); }
516 TypeInfo m_typeRet
; // return type
518 int m_flags
; // bit mask of the value from the enum above
520 ArrayParamInfo m_params
;
523 WX_DEFINE_ARRAY(MethodInfo
*, ArrayMethodInfo
);
524 WX_DEFINE_ARRAY(ArrayMethodInfo
*, ArrayMethodInfos
);
526 // first array contains the names of all classes we found, the second has a
527 // pointer to the array of methods of the given class at the same index as
528 // the class name appears in m_classes
529 wxArrayString m_classes
;
530 ArrayMethodInfos m_methods
;
532 // are we checking parameter names?
533 bool m_checkParamNames
;
536 DocManager(const DocManager
&);
537 DocManager
& operator=(const DocManager
&);
540 // =============================================================================
542 // =============================================================================
544 // this function never returns
547 wxString prog
= wxTheApp
->argv
[0];
548 wxString basename
= prog
.AfterLast('/');
551 basename
= prog
.AfterLast('\\');
557 "usage: %s [global options] <mode> [mode options] <files...>\n"
559 " where global options are:\n"
562 " -H give this usage message\n"
563 " -V print the version info\n"
564 " -i file file with classes/function to ignore\n"
566 " where mode is one of: dump, diff\n"
568 " dump means generate .tex files for TeX2RTF converter from specified\n"
569 " headers files, mode options are:\n"
570 " -f overwrite existing files\n"
571 " -o outdir directory for generated files\n"
573 " diff means compare the set of methods documented .tex file with the\n"
574 " methods declared in the header:\n"
575 " %s diff <file.h> <files.tex...>.\n"
576 " mode specific options are:\n"
577 " -p do check parameter names (not done by default)\n"
578 "\n", basename
.c_str(), basename
.c_str());
583 int HelpGenApp::OnRun()
596 wxArrayString filesH
, filesTeX
;
597 wxString directoryOut
, // directory for 'dmup' output
598 ignoreFile
; // file with classes/functions to ignore
599 bool overwrite
= FALSE
, // overwrite existing files during 'dump'?
600 paramNames
= FALSE
; // check param names during 'diff'?
602 for ( int current
= 1; current
< argc
; current
++ ) {
603 // all options have one letter
604 if ( argv
[current
][0] == '-' ) {
605 if ( argv
[current
][2] == '\0' ) {
606 switch ( argv
[current
][1] ) {
609 wxLog::GetActiveTarget()->SetVerbose();
614 wxLog::GetActiveTarget()->SetVerbose(FALSE
);
624 wxLogMessage("HelpGen version %s\n"
625 "(c) 1999-2001 Vadim Zeitlin\n",
626 GetVersionString().c_str());
631 if ( current
>= argc
) {
632 wxLogError("-i option requires an argument.");
637 ignoreFile
= argv
[current
];
641 if ( mode
!= Mode_Diff
) {
642 wxLogError("-p is only valid with diff.");
651 if ( mode
!= Mode_Dump
) {
652 wxLogError("-f is only valid with dump.");
661 if ( mode
!= Mode_Dump
) {
662 wxLogError("-o is only valid with dump.");
668 if ( current
>= argc
) {
669 wxLogError("-o option requires an argument.");
674 directoryOut
= argv
[current
];
675 if ( !!directoryOut
) {
676 // terminate with a '/' if it doesn't have it
677 switch ( directoryOut
.Last() ) {
688 //else: it's empty, do nothing
693 wxLogError("unknown option '%s'", argv
[current
]);
698 wxLogError("only one letter options are allowed, not '%s'.",
702 // only get here after a break from switch or from else branch of if
707 if ( mode
== Mode_None
) {
708 if ( strcmp(argv
[current
], "diff") == 0 )
710 else if ( strcmp(argv
[current
], "dump") == 0 )
713 wxLogError("unknown mode '%s'.", argv
[current
]);
719 if ( mode
== Mode_Dump
|| filesH
.IsEmpty() ) {
720 filesH
.Add(argv
[current
]);
723 // 2nd files and further are TeX files in diff mode
724 wxASSERT( mode
== Mode_Diff
);
726 filesTeX
.Add(argv
[current
]);
732 // create a parser object and a visitor derivation
733 CJSourceParser parser
;
734 HelpGenVisitor
visitor(directoryOut
, overwrite
);
735 if ( !!ignoreFile
&& mode
== Mode_Dump
)
736 visitor
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
738 spContext
*ctxTop
= NULL
;
740 // parse all header files
741 size_t nFiles
= filesH
.GetCount();
742 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
743 wxString header
= filesH
[n
];
744 ctxTop
= parser
.ParseFile(header
);
746 wxLogWarning("Header file '%s' couldn't be processed.",
749 else if ( mode
== Mode_Dump
) {
750 ((spFile
*)ctxTop
)->mFileName
= header
;
751 visitor
.VisitAll(*ctxTop
);
758 #endif // __WXDEBUG__
761 // parse all TeX files
762 if ( mode
== Mode_Diff
) {
764 wxLogError("Can't complete diff.");
770 DocManager
docman(paramNames
);
772 size_t nFiles
= filesTeX
.GetCount();
773 for ( size_t n
= 0; n
< nFiles
; n
++ ) {
774 wxString file
= filesTeX
[n
];
775 if ( !docman
.ParseTeXFile(file
) ) {
776 wxLogWarning("TeX file '%s' couldn't be processed.",
782 docman
.GetIgnoreHandler().AddNamesFromFile(ignoreFile
);
784 docman
.DumpDifferences(ctxTop
);
790 int main(int argc
, char **argv
)
792 wxInitializer initializer
;
795 fprintf(stderr
, "Failed to initialize the wxWindows library, aborting.");
805 // -----------------------------------------------------------------------------
806 // HelpGenVisitor implementation
807 // -----------------------------------------------------------------------------
809 HelpGenVisitor::HelpGenVisitor(const wxString
& directoryOut
,
811 : m_directoryOut(directoryOut
)
813 m_overwrite
= overwrite
;
818 void HelpGenVisitor::Reset()
822 m_inMethodSection
= FALSE
;
827 m_textStoredTypedefs
=
828 m_textStoredFunctionComment
= "";
830 m_arrayFuncDocs
.Empty();
832 m_storedEnums
.Empty();
833 m_storedEnumsVerb
.Empty();
837 void HelpGenVisitor::InsertTypedefDocs()
839 m_file
.WriteTeX(m_textStoredTypedefs
);
840 m_textStoredTypedefs
.Empty();
843 void HelpGenVisitor::InsertEnumDocs()
845 size_t count
= m_storedEnums
.GetCount();
846 for ( size_t n
= 0; n
< count
; n
++ )
848 m_file
.WriteTeX(m_storedEnums
[n
]);
849 m_file
.WriteVerbatim(m_storedEnumsVerb
[n
] + '\n');
852 m_storedEnums
.Empty();
853 m_storedEnumsVerb
.Empty();
856 void HelpGenVisitor::InsertDataStructuresHeader()
858 if ( !m_inTypesSection
) {
859 m_inTypesSection
= TRUE
;
861 m_file
.WriteVerbatim("\\wxheading{Data structures}\n\n");
865 void HelpGenVisitor::InsertMethodsHeader()
867 if ( !m_inMethodSection
) {
868 m_inMethodSection
= TRUE
;
870 m_file
.WriteVerbatim( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
874 void HelpGenVisitor::CloseFunction()
876 if ( !m_funcName
.empty() ) {
877 if ( m_isFirstParam
) {
879 m_textFunc
<< "\\void";
882 m_textFunc
<< "}\n\n";
884 if ( !m_textStoredFunctionComment
.IsEmpty() ) {
885 m_textFunc
<< m_textStoredFunctionComment
<< '\n';
888 m_arrayFuncDocs
.Add(new FunctionDocEntry(m_funcName
, m_textFunc
));
894 void HelpGenVisitor::CloseClass()
897 size_t count
= m_arrayFuncDocs
.GetCount();
899 FunctionDocEntry::classname
= m_classname
;
900 m_arrayFuncDocs
.Sort(FunctionDocEntry::Compare
);
902 for ( size_t n
= 0; n
< count
; n
++ ) {
903 m_file
.WriteTeX(m_arrayFuncDocs
[n
].text
);
906 m_arrayFuncDocs
.Empty();
914 void HelpGenVisitor::EndVisit()
920 m_fileHeader
.Empty();
924 wxLogVerbose("%s: finished generating for the current file.",
925 GetCurrentTime("%H:%M:%S"));
928 void HelpGenVisitor::VisitFile( spFile
& file
)
930 m_fileHeader
= file
.mFileName
;
931 wxLogVerbose("%s: started generating docs for classes from file '%s'...",
932 GetCurrentTime("%H:%M:%S"), m_fileHeader
.c_str());
935 void HelpGenVisitor::VisitClass( spClass
& cl
)
939 wxString name
= cl
.GetName();
941 if ( m_ignoreNames
.IgnoreClass(name
) ) {
942 wxLogVerbose("Skipping ignored class '%s'.", name
.c_str());
947 // the file name is built from the class name by removing the leading "wx"
948 // if any and converting it to the lower case
950 if ( name(0, 2) == "wx" ) {
951 filename
<< name
.c_str() + 2;
957 filename
.MakeLower();
959 filename
.Prepend(m_directoryOut
);
961 if ( !m_overwrite
&& wxFile::Exists(filename
) ) {
962 wxLogError("Won't overwrite existing file '%s' - please use '-f'.",
968 m_inClass
= m_file
.Open(filename
, wxFile::write
);
970 wxLogError("Can't generate documentation for the class '%s'.",
977 m_inTypesSection
= FALSE
;
979 wxLogInfo("Created new file '%s' for class '%s'.",
980 filename
.c_str(), name
.c_str());
982 // write out the header
985 "%% automatically generated by HelpGen %s from\n"
990 "\\section{\\class{%s}}\\label{%s}\n\n",
991 GetVersionString().c_str(),
992 m_fileHeader
.c_str(),
993 GetCurrentTime("%d/%b/%y %H:%M:%S"),
995 wxString(name
).MakeLower().c_str());
997 m_file
.WriteVerbatim(header
);
999 // the entire text we're writing to file
1002 // if the header includes other headers they must be related to it... try to
1003 // automatically generate the "See also" clause
1004 if ( !m_headers
.IsEmpty() ) {
1005 // correspondence between wxWindows headers and class names
1006 static const char *headers
[] = {
1015 // NULL here means not to insert anything in "See also" for the
1016 // corresponding header
1017 static const char *classes
[] = {
1026 wxASSERT_MSG( WXSIZEOF(headers
) == WXSIZEOF(classes
),
1027 "arrays must be in sync!" );
1029 wxArrayInt interestingClasses
;
1031 size_t count
= m_headers
.Count(), index
;
1032 for ( size_t n
= 0; n
< count
; n
++ ) {
1033 wxString baseHeaderName
= m_headers
[n
].Before('.');
1034 if ( baseHeaderName(0, 3) != "wx/" )
1037 baseHeaderName
.erase(0, 3);
1038 for ( index
= 0; index
< WXSIZEOF(headers
); index
++ ) {
1039 if ( Stricmp(baseHeaderName
, headers
[index
]) == 0 )
1043 if ( (index
< WXSIZEOF(headers
)) && classes
[index
] ) {
1044 // interesting header
1045 interestingClasses
.Add(index
);
1049 if ( !interestingClasses
.IsEmpty() ) {
1050 // do generate "See also" clause
1051 totalText
<< "\\wxheading{See also:}\n\n";
1053 count
= interestingClasses
.Count();
1054 for ( index
= 0; index
< count
; index
++ ) {
1058 totalText
<< MakeHelpref(classes
[interestingClasses
[index
]]);
1061 totalText
<< "\n\n";
1065 // the comment before the class generally explains what is it for so put it
1066 // in place of the class description
1067 if ( cl
.HasComments() ) {
1068 wxString comment
= GetAllComments(cl
);
1070 totalText
<< '\n' << comment
<< '\n';
1073 // derived from section
1074 wxString derived
= "\\wxheading{Derived from}\n\n";
1076 const StrListT
& baseClasses
= cl
.mSuperClassNames
;
1077 if ( baseClasses
.size() == 0 ) {
1078 derived
<< "No base class";
1082 for ( StrListT::const_iterator i
= baseClasses
.begin();
1083 i
!= baseClasses
.end();
1086 // separate from the previous one
1087 derived
<< "\\\\\n";
1093 wxString baseclass
= *i
;
1094 derived
<< "\\helpref{" << baseclass
<< "}";
1095 derived
<< "{" << baseclass
.MakeLower() << "}";
1098 totalText
<< derived
<< "\n\n";
1100 // write all this to file
1101 m_file
.WriteTeX(totalText
);
1103 // if there were any enums/typedefs before, insert their documentation now
1104 InsertDataStructuresHeader();
1105 InsertTypedefDocs();
1109 void HelpGenVisitor::VisitEnumeration( spEnumeration
& en
)
1113 if ( m_inMethodSection
) {
1114 // FIXME that's a bug, but tell the user aboit it nevertheless... we
1115 // should be smart enough to process even the enums which come after the
1117 wxLogWarning("enum '%s' ignored, please put it before the class "
1118 "methods.", en
.GetName().c_str());
1122 // simply copy the enum text in the docs
1123 wxString enumeration
= GetAllComments(en
),
1126 enumerationVerb
<< "\\begin{verbatim}\n"
1128 << "\n\\end{verbatim}\n";
1130 // remember for later use if we're not inside a class yet
1132 m_storedEnums
.Add(enumeration
);
1133 m_storedEnumsVerb
.Add(enumerationVerb
);
1136 // write the header for this section if not done yet
1137 InsertDataStructuresHeader();
1139 m_file
.WriteTeX(enumeration
);
1140 m_file
.WriteVerbatim(enumerationVerb
);
1141 m_file
.WriteVerbatim('\n');
1145 void HelpGenVisitor::VisitTypeDef( spTypeDef
& td
)
1149 if ( m_inMethodSection
) {
1150 // FIXME that's a bug, but tell the user aboit it nevertheless...
1151 wxLogWarning("typedef '%s' ignored, please put it before the class "
1152 "methods.", td
.GetName().c_str());
1156 wxString typedefdoc
;
1157 typedefdoc
<< "{\\small \\begin{verbatim}\n"
1158 << "typedef " << td
.mOriginalType
<< ' ' << td
.GetName()
1159 << "\n\\end{verbatim}}\n"
1160 << GetAllComments(td
);
1162 // remember for later use if we're not inside a class yet
1164 if ( !m_textStoredTypedefs
.IsEmpty() ) {
1165 m_textStoredTypedefs
<< '\n';
1168 m_textStoredTypedefs
<< typedefdoc
;
1171 // write the header for this section if not done yet
1172 InsertDataStructuresHeader();
1175 m_file
.WriteTeX(typedefdoc
);
1179 void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine
& pd
)
1181 switch ( pd
.GetStatementType() ) {
1182 case SP_PREP_DEF_INCLUDE_FILE
:
1183 m_headers
.Add(pd
.CPP_GetIncludedFileNeme());
1186 case SP_PREP_DEF_DEFINE_SYMBOL
:
1187 // TODO decide if it's a constant and document it if it is
1192 void HelpGenVisitor::VisitAttribute( spAttribute
& attr
)
1196 // only document the public member variables
1197 if ( !m_inClass
|| !attr
.IsPublic() )
1200 wxLogWarning("Ignoring member variable '%s'.", attr
.GetName().c_str());
1203 void HelpGenVisitor::VisitOperation( spOperation
& op
)
1208 // we don't generate docs right now - either we ignore this class
1209 // entirely or we couldn't open the file
1213 if ( !op
.IsInClass() ) {
1214 // TODO document global functions
1215 wxLogWarning("skipped global function '%s'.", op
.GetName().c_str());
1220 if ( op
.mVisibility
== SP_VIS_PRIVATE
) {
1221 // FIXME should we document protected functions?
1225 m_classname
= op
.GetClass().GetName();
1226 wxString funcname
= op
.GetName();
1228 if ( m_ignoreNames
.IgnoreMethod(m_classname
, funcname
) ) {
1229 wxLogVerbose("Skipping ignored '%s::%s'.",
1230 m_classname
.c_str(), funcname
.c_str());
1235 InsertMethodsHeader();
1238 m_funcName
= funcname
;
1239 m_isFirstParam
= TRUE
;
1241 m_textStoredFunctionComment
= GetAllComments(op
);
1243 // start function documentation
1246 // check for the special case of dtor
1248 if ( (funcname
[0] == '~') && (m_classname
== funcname
.c_str() + 1) ) {
1249 dtor
.Printf("\\destruct{%s}", m_classname
.c_str());
1253 m_textFunc
.Printf("\n"
1254 "\\membersection{%s::%s}\\label{%s}\n"
1256 "\\%sfunc{%s%s}{%s}{",
1257 m_classname
.c_str(), funcname
.c_str(),
1258 MakeLabel(m_classname
, funcname
).c_str(),
1259 op
.mIsConstant
? "const" : "",
1260 op
.mIsVirtual
? "virtual " : "",
1261 op
.mRetType
.c_str(),
1265 void HelpGenVisitor::VisitParameter( spParameter
& param
)
1267 if ( m_funcName
.empty() )
1270 if ( m_isFirstParam
) {
1271 m_isFirstParam
= FALSE
;
1277 m_textFunc
<< "\\param{" << param
.mType
<< " }{" << param
.GetName();
1278 wxString defvalue
= param
.mInitVal
;
1279 if ( !defvalue
.IsEmpty() ) {
1280 m_textFunc
<< " = " << defvalue
;
1286 // ---------------------------------------------------------------------------
1288 // ---------------------------------------------------------------------------
1290 DocManager::DocManager(bool checkParamNames
)
1292 m_checkParamNames
= checkParamNames
;
1295 size_t DocManager::TryMatch(const char *str
, const char *match
)
1297 size_t lenMatch
= 0;
1298 while ( str
[lenMatch
] == match
[lenMatch
] ) {
1301 if ( match
[lenMatch
] == '\0' )
1308 bool DocManager::SkipUntil(const char **pp
, char c
)
1310 const char *p
= *pp
;
1326 bool DocManager::SkipSpaceUntil(const char **pp
, char c
)
1328 const char *p
= *pp
;
1330 if ( !isspace(*p
) || *p
== '\0' )
1344 wxString
DocManager::ExtractStringBetweenBraces(const char **pp
)
1348 if ( !SkipSpaceUntil(pp
, '{') ) {
1349 wxLogWarning("file %s(%d): '{' expected after '\\param'",
1350 m_filename
.c_str(), m_line
);
1354 const char *startParam
= ++*pp
; // skip '{'
1356 if ( !SkipUntil(pp
, '}') ) {
1357 wxLogWarning("file %s(%d): '}' expected after '\\param'",
1358 m_filename
.c_str(), m_line
);
1361 result
= wxString(startParam
, (*pp
)++ - startParam
);
1368 bool DocManager::ParseTeXFile(const wxString
& filename
)
1370 m_filename
= filename
;
1372 wxFile
file(m_filename
, wxFile::read
);
1373 if ( !file
.IsOpened() )
1376 off_t len
= file
.Length();
1377 if ( len
== wxInvalidOffset
)
1380 char *buf
= new char[len
+ 1];
1383 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1389 // reinit everything
1392 wxLogVerbose("%s: starting to parse doc file '%s'.",
1393 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1395 // the name of the class from the last "\membersection" command: we assume
1396 // that the following "\func" or "\constfunc" always documents a method of
1397 // this class (and it should always be like that in wxWindows documentation)
1400 for ( const char *current
= buf
; current
- buf
< len
; current
++ ) {
1401 // FIXME parsing is awfully inefficient
1403 if ( *current
== '%' ) {
1404 // comment, skip until the end of line
1406 SkipUntil(¤t
, '\n');
1411 // all the command we're interested in start with '\\'
1412 while ( *current
!= '\\' && *current
!= '\0' ) {
1413 if ( *current
++ == '\n' )
1417 if ( *current
== '\0' ) {
1418 // no more TeX commands left
1422 current
++; // skip '\\'
1430 } foundCommand
= Nothing
;
1432 size_t lenMatch
= TryMatch(current
, "func");
1434 foundCommand
= Func
;
1437 lenMatch
= TryMatch(current
, "constfunc");
1439 foundCommand
= ConstFunc
;
1441 lenMatch
= TryMatch(current
, "membersection");
1444 foundCommand
= MemberSect
;
1448 if ( foundCommand
== Nothing
)
1451 current
+= lenMatch
;
1453 if ( !SkipSpaceUntil(¤t
, '{') ) {
1454 wxLogWarning("file %s(%d): '{' expected after \\func, "
1455 "\\constfunc or \\membersection.",
1456 m_filename
.c_str(), m_line
);
1463 if ( foundCommand
== MemberSect
) {
1464 // what follows has the form <classname>::<funcname>
1465 const char *startClass
= current
;
1466 if ( !SkipUntil(¤t
, ':') || *(current
+ 1) != ':' ) {
1467 wxLogWarning("file %s(%d): '::' expected after "
1468 "\\membersection.", m_filename
.c_str(), m_line
);
1471 classname
= wxString(startClass
, current
- startClass
);
1472 TeXUnfilter(&classname
);
1478 // extract the return type
1479 const char *startRetType
= current
;
1481 if ( !SkipUntil(¤t
, '}') ) {
1482 wxLogWarning("file %s(%d): '}' expected after return type",
1483 m_filename
.c_str(), m_line
);
1488 wxString returnType
= wxString(startRetType
, current
- startRetType
);
1489 TeXUnfilter(&returnType
);
1492 if ( !SkipSpaceUntil(¤t
, '{') ) {
1493 wxLogWarning("file %s(%d): '{' expected after return type",
1494 m_filename
.c_str(), m_line
);
1500 const char *funcEnd
= current
;
1501 if ( !SkipUntil(&funcEnd
, '}') ) {
1502 wxLogWarning("file %s(%d): '}' expected after function name",
1503 m_filename
.c_str(), m_line
);
1508 wxString funcName
= wxString(current
, funcEnd
- current
);
1509 current
= funcEnd
+ 1;
1511 // trim spaces from both sides
1512 funcName
.Trim(FALSE
);
1513 funcName
.Trim(TRUE
);
1515 // special cases: '$...$' may be used for LaTeX inline math, remove the
1517 if ( funcName
.Find('$') != wxNOT_FOUND
) {
1519 for ( const char *p
= funcName
.c_str(); *p
!= '\0'; p
++ ) {
1520 if ( *p
!= '$' && !isspace(*p
) )
1527 // \destruct{foo} is really ~foo
1528 if ( funcName
[0u] == '\\' ) {
1529 size_t len
= strlen("\\destruct{");
1530 if ( funcName(0, len
) != "\\destruct{" ) {
1531 wxLogWarning("file %s(%d): \\destruct expected",
1532 m_filename
.c_str(), m_line
);
1537 funcName
.erase(0, len
);
1538 funcName
.Prepend('~');
1540 if ( !SkipSpaceUntil(¤t
, '}') ) {
1541 wxLogWarning("file %s(%d): '}' expected after destructor",
1542 m_filename
.c_str(), m_line
);
1547 funcEnd
++; // there is an extra '}' to count
1550 TeXUnfilter(&funcName
);
1553 current
= funcEnd
+ 1; // skip '}'
1554 if ( !SkipSpaceUntil(¤t
, '{') ||
1555 (current
++, !SkipSpaceUntil(¤t
, '\\')) ) {
1556 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1557 m_filename
.c_str(), m_line
);
1562 wxArrayString paramNames
, paramTypes
, paramValues
;
1564 bool isVararg
= FALSE
;
1566 current
++; // skip '\\'
1567 lenMatch
= TryMatch(current
, "void");
1569 lenMatch
= TryMatch(current
, "param");
1570 while ( lenMatch
&& (current
- buf
< len
) ) {
1571 current
+= lenMatch
;
1573 // now come {paramtype}{paramname}
1574 wxString paramType
= ExtractStringBetweenBraces(¤t
);
1575 if ( !!paramType
) {
1576 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1577 if ( !!paramText
) {
1578 // the param declaration may contain default value
1579 wxString paramName
= paramText
.BeforeFirst('='),
1580 paramValue
= paramText
.AfterFirst('=');
1582 // sanitize all strings
1583 TeXUnfilter(¶mValue
);
1584 TeXUnfilter(¶mName
);
1585 TeXUnfilter(¶mType
);
1587 paramValues
.Add(paramValue
);
1588 paramNames
.Add(paramName
);
1589 paramTypes
.Add(paramType
);
1594 wxString paramText
= ExtractStringBetweenBraces(¤t
);
1595 if ( paramText
== "..." ) {
1599 wxLogWarning("Parameters of '%s::%s' are in "
1601 classname
.c_str(), funcName
.c_str());
1606 current
= SkipSpaces(current
);
1607 if ( *current
== ',' || *current
== '}' ) {
1608 current
= SkipSpaces(++current
);
1610 lenMatch
= TryMatch(current
, "\\param");
1613 wxLogWarning("file %s(%d): ',' or '}' expected after "
1614 "'\\param'", m_filename
.c_str(), m_line
);
1620 // if we got here there was no '\\void', so must have some params
1621 if ( paramNames
.IsEmpty() ) {
1622 wxLogWarning("file %s(%d): '\\param' or '\\void' expected",
1623 m_filename
.c_str(), m_line
);
1629 // verbose diagnostic output
1631 size_t param
, paramCount
= paramNames
.GetCount();
1632 for ( param
= 0; param
< paramCount
; param
++ ) {
1637 paramsAll
<< paramTypes
[param
] << ' ' << paramNames
[param
];
1640 wxLogVerbose("file %s(%d): found '%s %s::%s(%s)%s'",
1641 m_filename
.c_str(), m_line
,
1646 foundCommand
== ConstFunc
? " const" : "");
1648 // store the info about the just found function
1649 ArrayMethodInfo
*methods
;
1650 int index
= m_classes
.Index(classname
);
1651 if ( index
== wxNOT_FOUND
) {
1652 m_classes
.Add(classname
);
1654 methods
= new ArrayMethodInfo
;
1655 m_methods
.Add(methods
);
1658 methods
= m_methods
[(size_t)index
];
1661 ArrayParamInfo params
;
1662 for ( param
= 0; param
< paramCount
; param
++ ) {
1663 params
.Add(new ParamInfo(paramTypes
[param
],
1665 paramValues
[param
]));
1668 MethodInfo
*method
= new MethodInfo(returnType
, funcName
, params
);
1669 if ( foundCommand
== ConstFunc
)
1670 method
->SetFlag(MethodInfo::Const
);
1672 method
->SetFlag(MethodInfo::Vararg
);
1674 methods
->Add(method
);
1679 wxLogVerbose("%s: finished parsing doc file '%s'.\n",
1680 GetCurrentTime("%H:%M:%S"), m_filename
.c_str());
1685 bool DocManager::DumpDifferences(spContext
*ctxTop
) const
1687 typedef MMemberListT::const_iterator MemberIndex
;
1689 bool foundDiff
= FALSE
;
1691 // flag telling us whether the given class was found at all in the header
1692 size_t nClass
, countClassesInDocs
= m_classes
.GetCount();
1693 bool *classExists
= new bool[countClassesInDocs
];
1694 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1695 classExists
[nClass
] = FALSE
;
1698 // ctxTop is normally an spFile
1699 wxASSERT( ctxTop
->GetContextType() == SP_CTX_FILE
);
1701 const MMemberListT
& classes
= ctxTop
->GetMembers();
1702 for ( MemberIndex i
= classes
.begin(); i
!= classes
.end(); i
++ ) {
1703 spContext
*ctx
= *i
;
1704 if ( ctx
->GetContextType() != SP_CTX_CLASS
) {
1705 // TODO process also global functions, macros, ...
1709 spClass
*ctxClass
= (spClass
*)ctx
;
1710 const wxString
& nameClass
= ctxClass
->mName
;
1711 int index
= m_classes
.Index(nameClass
);
1712 if ( index
== wxNOT_FOUND
) {
1713 if ( !m_ignoreNames
.IgnoreClass(nameClass
) ) {
1716 wxLogError("Class '%s' is not documented at all.",
1720 // it makes no sense to check for its functions
1724 classExists
[index
] = TRUE
;
1727 // array of method descriptions for this class
1728 const ArrayMethodInfo
& methods
= *(m_methods
[index
]);
1729 size_t nMethod
, countMethods
= methods
.GetCount();
1731 // flags telling if we already processed given function
1732 bool *methodExists
= new bool[countMethods
];
1733 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1734 methodExists
[nMethod
] = FALSE
;
1737 wxArrayString aOverloadedMethods
;
1739 const MMemberListT
& functions
= ctxClass
->GetMembers();
1740 for ( MemberIndex j
= functions
.begin(); j
!= functions
.end(); j
++ ) {
1742 if ( ctx
->GetContextType() != SP_CTX_OPERATION
)
1745 spOperation
*ctxMethod
= (spOperation
*)ctx
;
1746 const wxString
& nameMethod
= ctxMethod
->mName
;
1748 // find all functions with the same name
1749 wxArrayInt aMethodsWithSameName
;
1750 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1751 if ( methods
[nMethod
]->GetName() == nameMethod
)
1752 aMethodsWithSameName
.Add(nMethod
);
1755 if ( aMethodsWithSameName
.IsEmpty() && ctxMethod
->IsPublic() ) {
1756 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1759 wxLogError("'%s::%s' is not documented.",
1761 nameMethod
.c_str());
1764 // don't check params
1767 else if ( aMethodsWithSameName
.GetCount() == 1 ) {
1768 index
= (size_t)aMethodsWithSameName
[0u];
1769 methodExists
[index
] = TRUE
;
1771 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1774 if ( !ctxMethod
->IsPublic() ) {
1775 wxLogWarning("'%s::%s' is documented but not public.",
1777 nameMethod
.c_str());
1780 // check that the flags match
1781 const MethodInfo
& method
= *(methods
[index
]);
1783 bool isVirtual
= ctxMethod
->mIsVirtual
;
1784 if ( isVirtual
!= method
.HasFlag(MethodInfo::Virtual
) ) {
1785 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1789 isVirtual
? "not " : "");
1792 bool isConst
= ctxMethod
->mIsConstant
;
1793 if ( isConst
!= method
.HasFlag(MethodInfo::Const
) ) {
1794 wxLogWarning("'%s::%s' is incorrectly documented as %s"
1798 isConst
? "not " : "");
1801 // check that the params match
1802 const MMemberListT
& params
= ctxMethod
->GetMembers();
1804 if ( params
.size() != method
.GetParamCount() ) {
1805 wxLogError("Incorrect number of parameters for '%s::%s' "
1806 "in the docs: should be %d instead of %d.",
1809 params
.size(), method
.GetParamCount());
1813 for ( MemberIndex k
= params
.begin();
1818 // what else can a function have?
1819 wxASSERT( ctx
->GetContextType() == SP_CTX_PARAMETER
);
1821 spParameter
*ctxParam
= (spParameter
*)ctx
;
1822 const ParamInfo
& param
= method
.GetParam(nParam
);
1823 if ( m_checkParamNames
&&
1824 (param
.GetName() != ctxParam
->mName
) ) {
1827 wxLogError("Parameter #%d of '%s::%s' should be "
1828 "'%s' and not '%s'.",
1832 ctxParam
->mName
.c_str(),
1833 param
.GetName().c_str());
1838 if ( param
.GetType() != ctxParam
->mType
) {
1841 wxLogError("Type of parameter '%s' of '%s::%s' "
1842 "should be '%s' and not '%s'.",
1843 ctxParam
->mName
.c_str(),
1846 ctxParam
->mType
.c_str(),
1847 param
.GetType().GetName().c_str());
1852 if ( param
.GetDefValue() != ctxParam
->mInitVal
) {
1853 wxLogWarning("Default value of parameter '%s' of "
1854 "'%s::%s' should be '%s' and not "
1856 ctxParam
->mName
.c_str(),
1859 ctxParam
->mInitVal
.c_str(),
1860 param
.GetDefValue().c_str());
1866 // TODO OVER add real support for overloaded methods
1868 if ( m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) )
1871 if ( aOverloadedMethods
.Index(nameMethod
) == wxNOT_FOUND
) {
1872 // mark all methods with this name as existing
1873 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1874 if ( methods
[nMethod
]->GetName() == nameMethod
)
1875 methodExists
[nMethod
] = TRUE
;
1878 aOverloadedMethods
.Add(nameMethod
);
1880 wxLogVerbose("'%s::%s' is overloaded and I'm too "
1881 "stupid to find the right match - skipping "
1882 "the param and flags checks.",
1884 nameMethod
.c_str());
1886 //else: warning already given
1890 for ( nMethod
= 0; nMethod
< countMethods
; nMethod
++ ) {
1891 if ( !methodExists
[nMethod
] ) {
1892 const wxString
& nameMethod
= methods
[nMethod
]->GetName();
1893 if ( !m_ignoreNames
.IgnoreMethod(nameClass
, nameMethod
) ) {
1896 wxLogError("'%s::%s' is documented but doesn't exist.",
1898 nameMethod
.c_str());
1903 delete [] methodExists
;
1906 // check that all classes we found in the docs really exist
1907 for ( nClass
= 0; nClass
< countClassesInDocs
; nClass
++ ) {
1908 if ( !classExists
[nClass
] ) {
1911 wxLogError("Class '%s' is documented but doesn't exist.",
1912 m_classes
[nClass
].c_str());
1916 delete [] classExists
;
1921 DocManager::~DocManager()
1923 WX_CLEAR_ARRAY(m_methods
);
1926 // ---------------------------------------------------------------------------
1927 // IgnoreNamesHandler implementation
1928 // ---------------------------------------------------------------------------
1930 int IgnoreNamesHandler::CompareIgnoreListEntries(IgnoreListEntry
*first
,
1931 IgnoreListEntry
*second
)
1933 // first compare the classes
1934 int rc
= first
->m_classname
.Cmp(second
->m_classname
);
1936 rc
= first
->m_funcname
.Cmp(second
->m_funcname
);
1941 bool IgnoreNamesHandler::AddNamesFromFile(const wxString
& filename
)
1943 wxFile
file(filename
, wxFile::read
);
1944 if ( !file
.IsOpened() )
1947 off_t len
= file
.Length();
1948 if ( len
== wxInvalidOffset
)
1951 char *buf
= new char[len
+ 1];
1954 if ( file
.Read(buf
, len
) == wxInvalidOffset
) {
1961 for ( const char *current
= buf
; ; current
++ ) {
1963 // skip DOS line separator
1964 if ( *current
== '\r' )
1968 if ( *current
== '\n' || *current
== '\0' ) {
1969 if ( line
[0u] != '#' ) {
1970 if ( line
.Find(':') != wxNOT_FOUND
) {
1971 wxString classname
= line
.BeforeFirst(':'),
1972 funcname
= line
.AfterLast(':');
1973 m_ignore
.Add(new IgnoreListEntry(classname
, funcname
));
1977 m_ignore
.Add(new IgnoreListEntry(line
, ""));
1982 if ( *current
== '\0' )
1997 // -----------------------------------------------------------------------------
1998 // global function implementation
1999 // -----------------------------------------------------------------------------
2001 static wxString
MakeLabel(const char *classname
, const char *funcname
)
2003 wxString
label(classname
);
2004 if ( funcname
&& funcname
[0] == '\\' ) {
2005 // we may have some special TeX macro - so far only \destruct exists,
2006 // but may be later others will be added
2007 static const char *macros
[] = { "destruct" };
2008 static const char *replacement
[] = { "dtor" };
2011 for ( n
= 0; n
< WXSIZEOF(macros
); n
++ ) {
2012 if ( strncmp(funcname
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) {
2018 if ( n
== WXSIZEOF(macros
) ) {
2019 wxLogWarning("unknown function name '%s' - leaving as is.",
2023 funcname
= replacement
[n
];
2028 // special treatment for operatorXXX() stuff because the C operators
2029 // are not valid in LaTeX labels
2031 if ( wxString(funcname
).StartsWith("operator", &oper
) ) {
2032 label
<< "operator";
2045 for ( n
= 0; n
< WXSIZEOF(operatorNames
); n
++ ) {
2046 if ( oper
== operatorNames
[n
].oper
) {
2047 label
<< operatorNames
[n
].name
;
2053 if ( n
== WXSIZEOF(operatorNames
) ) {
2054 wxLogWarning("unknown operator '%s' - making dummy label.",
2060 else // simply use the func name
2071 static wxString
MakeHelpref(const char *argument
)
2074 helpref
<< "\\helpref{" << argument
<< "}{" << MakeLabel(argument
) << '}';
2079 static void TeXFilter(wxString
* str
)
2081 // TeX special which can be quoted (don't include backslash nor braces as
2083 static wxRegEx
reNonSpecialSpecials("[#$%&_]"),
2087 reNonSpecialSpecials
.ReplaceAll(str
, "\\\\\\0");
2089 // can't quote these ones as they produce accents when preceded by
2090 // backslash, so put them inside verb
2091 reAccents
.ReplaceAll(str
, "\\\\verb|\\0|");
2094 static void TeXUnfilter(wxString
* str
)
2096 // FIXME may be done much more quickly
2101 static wxRegEx
reNonSpecialSpecials("\\\\([#$%&_{}])"),
2102 reAccents("\\\\verb|([~^])|");
2104 reNonSpecialSpecials
.ReplaceAll(str
, "\\1");
2105 reAccents
.ReplaceAll(str
, "\\1");
2108 static wxString
GetAllComments(const spContext
& ctx
)
2111 const MCommentListT
& commentsList
= ctx
.GetCommentList();
2112 for ( MCommentListT::const_iterator i
= commentsList
.begin();
2113 i
!= commentsList
.end();
2115 wxString comment
= (*i
)->GetText();
2117 // don't take comments like "// ----------" &c
2118 comment
.Trim(FALSE
);
2120 comment
== wxString(comment
[0u], comment
.length() - 1) + '\n' )
2123 comments
<< comment
;
2129 static const char *GetCurrentTime(const char *timeFormat
)
2131 static char s_timeBuffer
[128];
2136 ptmNow
= localtime(&timeNow
);
2138 strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
);
2140 return s_timeBuffer
;
2143 static const wxString
GetVersionString()
2145 wxString version
= "$Revision$";
2146 wxRegEx("^\\$Revision$$").ReplaceFirst(&version
, "\\1");
2152 Revision 1.18 2002/01/03 12:02:47 JS
2153 Added main() and corrected VC++ project settings
2155 Revision 1.17 2001/11/30 21:43:35 VZ
2156 now the methods are sorted in the correct order in the generated docs
2158 Revision 1.16 2001/11/28 19:27:33 VZ
2159 HelpGen doesn't work in GUI mode
2161 Revision 1.15 2001/11/22 21:59:58 GD
2162 use "..." instead of <...> for wx headers
2164 Revision 1.14 2001/07/19 13:51:29 VZ
2165 fixes to version string
2167 Revision 1.13 2001/07/19 13:44:57 VZ
2168 1. compilation fixes
2169 2. don't quote special characters inside verbatim environment
2171 Revision 1.12 2000/10/09 13:53:33 juliansmart
2173 Doc corrections; added HelpGen project files
2175 Revision 1.11 2000/07/15 19:50:42 cvsuser
2178 Revision 1.10.2.2 2000/03/27 15:33:10 VZ
2179 don't trasnform output dir name to lower case
2181 Revision 1.10 2000/03/11 10:05:23 VS
2182 now compiles with wxBase
2184 Revision 1.9 2000/01/16 13:25:21 VS
2185 compilation fixes (gcc)
2187 Revision 1.8 1999/09/13 14:29:39 JS
2189 Made HelpGen into a wxWin app (still uses command-line args); moved includes
2190 into src for simplicity; added VC++ 5 project file
2192 Revision 1.7 1999/02/21 22:32:32 VZ
2193 1. more C++ parser fixes - now it almost parses wx/string.h
2194 a) #if/#ifdef/#else (very) limited support
2195 b) param type fix - now indirection chars are correctly handled
2196 c) class/struct/union distinction
2197 d) public/private fixes
2198 e) Dump() function added - very useful for debugging
2200 2. option to ignore parameter names during 'diff' (in fact, they're ignored
2201 by default, and this option switches it on)
2203 Revision 1.6 1999/02/20 23:00:26 VZ
2204 1. new 'diff' mode which seems to work
2205 2. output files are not overwritten in 'dmup' mode
2206 3. fixes for better handling of const functions and operators
2207 ----------------------------
2209 date: 1999/02/15 23:07:25; author: VZ; state: Exp; lines: +106 -45
2210 1. Parser improvements
2211 a) const and virtual methods are parsed correctly (not static yet)
2212 b) "const" which is part of the return type is not swallowed
2214 2. HelpGen improvements: -o outputdir parameter added to the cmd line,
2215 "//---------" kind comments discarded now.
2216 ----------------------------
2218 date: 1999/01/13 14:23:31; author: JS; state: Exp; lines: +4 -4
2220 some tweaks to HelpGen
2221 ----------------------------
2223 date: 1999/01/09 20:18:03; author: JS; state: Exp; lines: +7 -2
2225 HelpGen starting to compile with VC++
2226 ----------------------------
2228 date: 1999/01/08 19:46:22; author: VZ; state: Exp; lines: +208 -35
2230 supports typedefs, generates "See also:" and adds "virtual " for virtual
2232 ----------------------------
2234 date: 1999/01/08 17:45:55; author: VZ; state: Exp;
2236 HelpGen is a prototype of the tool for automatic generation of the .tex files
2237 for wxWindows documentation from C++ headers
2240 /* vi: set tw=80 et ts=4 sw=4: */