1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Main program file for HelpGen
4 // Author: Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Copyright: (c) 1999 VZ
10 /////////////////////////////////////////////////////////////////////////////
15 (i) small fixes in the current version
17 +1. Quote special TeX characters like '&' and '_' (=> derive from wxFile)
19 3. Document global variables
23 (ii) plans for version 2
24 1. Use wxTextFile for direct file access to avoid one scan method problems
25 2. Use command line parsrer class for the options
29 // =============================================================================
31 // =============================================================================
33 // -----------------------------------------------------------------------------
35 // -----------------------------------------------------------------------------
38 #include "wx/wxprec.h"
41 #include <wx/string.h>
44 #include <wx/dynarray.h>
47 // C++ parsing classes
54 // -----------------------------------------------------------------------------
56 // -----------------------------------------------------------------------------
58 // return the label for the given function name (i.e. argument of \label)
59 static wxString
MakeLabel(const char *classname
, const char *funcname
= NULL
);
61 // return the whole \helpref{arg}{arg_label} string
62 static wxString
MakeHelpref(const char *argument
);
64 // quotes special TeX characters in place
65 static void TeXFilter(wxString
* str
);
67 // get all comments associated with this context
68 static wxString
GetAllComments(const spContext
& ctx
);
70 // get the string with current time (returns pointer to static buffer)
71 // timeFormat is used for the call of strftime(3)
72 static const char *GetCurrentTime(const char *timeFormat
);
74 // -----------------------------------------------------------------------------
76 // -----------------------------------------------------------------------------
78 // add a function which sanitazes the string before writing it to the file
79 class wxTeXFile
: public wxFile
82 wxTeXFile() : wxFile() { }
84 bool WriteTeX(const wxString
& s
)
89 return wxFile::Write(t
);
93 class HelpGenVisitor
: public spVisitor
99 virtual void VisitFile( spFile
& fl
);
100 virtual void VisitClass( spClass
& cl
);
101 virtual void VisitEnumeration( spEnumeration
& en
);
102 virtual void VisitTypeDef( spTypeDef
& td
);
103 virtual void VisitPreprocessorLine( spPreprocessorLine
& pd
);
104 virtual void VisitAttribute( spAttribute
& attr
);
105 virtual void VisitOperation( spOperation
& op
);
106 virtual void VisitParameter( spParameter
& param
);
110 // shut up g++ warning (ain't it stupid?)
111 virtual ~HelpGenVisitor() { }
114 // (re)initialize the state
117 // insert documentation for enums/typedefs coming immediately before the
118 // class declaration into the class documentation
119 void InsertTypedefDocs();
120 void InsertEnumDocs();
122 // write the headers for corresponding sections (only once)
123 void InsertDataStructuresHeader();
124 void InsertMethodsHeader();
126 // terminate the function documentation if it was started
127 void CloseFunction();
129 wxTeXFile m_file
; // file we're writing to now
132 bool m_inClass
, // TRUE after file successfully opened
133 m_inTypesSection
, // enums & typedefs go there
134 m_inMethodSection
, // functions go here
135 m_isFirstParam
, // first parameter of current function?
136 m_inFunction
; // we're parsing a function declaration
138 // holders for "saved" documentation
139 wxString m_textStoredEnums
,
140 m_textStoredTypedefs
,
141 m_textStoredFunctionComment
;
143 // headers included by this file
144 wxArrayString m_headers
;
147 // -----------------------------------------------------------------------------
149 // -----------------------------------------------------------------------------
151 // =============================================================================
153 // =============================================================================
155 // this function never returns
158 wxLogError("usage: HelpGen [-q|-v] <header files...>\n");
163 int main(int argc
, char **argv
)
170 for ( first
= 1; (first
< argc
) && argv
[first
][0] == '-'; first
++ ) {
171 switch ( argv
[first
][1] ) {
174 wxLog::GetActiveTarget()->SetVerbose();
179 wxLog::GetActiveTarget()->SetVerbose(false);
187 // create a parser object and a visitor derivation
188 CJSourceParser parser
;
189 HelpGenVisitor visitor
;
192 for ( int i
= first
; i
< argc
; i
++ ) {
193 spContext
*ctxTop
= parser
.ParseFile(argv
[i
]);
195 wxLogWarning("File '%s' couldn't be processed.", argv
[i
]);
198 ((spFile
*)ctxTop
)->mFileName
= argv
[i
];
199 visitor
.VisitAll(*ctxTop
);
207 // -----------------------------------------------------------------------------
208 // HelpGenVisitor implementation
209 // -----------------------------------------------------------------------------
211 HelpGenVisitor::HelpGenVisitor()
216 void HelpGenVisitor::Reset()
221 m_inMethodSection
= false;
223 m_textStoredTypedefs
=
225 m_textStoredFunctionComment
= "";
229 void HelpGenVisitor::InsertTypedefDocs()
231 m_file
.WriteTeX(m_textStoredTypedefs
);
232 m_textStoredTypedefs
.Empty();
235 void HelpGenVisitor::InsertEnumDocs()
237 m_file
.WriteTeX(m_textStoredEnums
);
238 m_textStoredEnums
.Empty();
241 void HelpGenVisitor::InsertDataStructuresHeader()
243 if ( !m_inTypesSection
) {
244 m_inTypesSection
= true;
246 m_file
.WriteTeX("\\wxheading{Data structures}\n\n");
250 void HelpGenVisitor::InsertMethodsHeader()
252 if ( !m_inMethodSection
) {
253 m_inMethodSection
= true;
255 m_file
.WriteTeX( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
259 void HelpGenVisitor::CloseFunction()
261 if ( m_inFunction
) {
262 m_inFunction
= false;
265 if ( m_isFirstParam
) {
267 totalText
<< "\\void";
270 totalText
<< "}\n\n";
272 if ( !m_textStoredFunctionComment
.IsEmpty() )
273 totalText
<< m_textStoredFunctionComment
<< '\n';
275 m_file
.WriteTeX(totalText
);
279 void HelpGenVisitor::EndVisit()
283 wxLogInfo("%s: finished parsing the current file.",
284 GetCurrentTime("%H:%M:%S"));
287 void HelpGenVisitor::VisitFile( spFile
& file
)
289 wxLogInfo("%s: started to parse classes from file '%s'...",
290 GetCurrentTime("%H:%M:%S"), file
.mFileName
.c_str());
293 void HelpGenVisitor::VisitClass( spClass
& cl
)
295 wxString name
= cl
.GetName();
297 // the file name is built from the class name by removing the leading "wx"
298 // if any and converting it to the lower case
299 wxString filename
= name
;
300 if ( filename(0, 2) == "wx" ) {
301 filename
.erase(0, 2);
304 filename
.MakeLower();
307 m_inClass
= m_file
.Open(filename
, wxFile::write
);
309 wxLogError("Can't generate documentation for the class '%s'.",
316 m_inTypesSection
= false;
318 wxLogInfo("Created new file '%s' for class '%s'.",
319 filename
.c_str(), name
.c_str());
321 // the entire text we're writing to file
324 // write out the header
327 header
.Printf("% automatically generated by HelpGen from %s at %s\n"
328 "\\section{\\class{%s}}\\label{%s}\n",
329 filename
.c_str(), GetCurrentTime("%d/%b/%y %H:%M:%S"),
330 name
.c_str(), wxString(name
).MakeLower().c_str());
332 totalText
<< header
<< '\n';
335 // if the header includes other headers they must be related to it... try to
336 // automatically generate the "See also" clause
337 if ( !m_headers
.IsEmpty() ) {
338 // correspondence between wxWindows headers and class names
339 static const char *headers
[] = {
348 // NULL here means not to insert anything in "See also" for the
349 // corresponding header
350 static const char *classes
[] = {
359 wxASSERT_MSG( WXSIZEOF(headers
) == WXSIZEOF(classes
),
360 "arrays must be in sync!" );
362 wxArrayInt interestingClasses
;
364 size_t count
= m_headers
.Count(), index
;
365 for ( size_t n
= 0; n
< count
; n
++ ) {
366 wxString baseHeaderName
= m_headers
[n
].Before('.');
367 if ( baseHeaderName(0, 3) != "wx/" )
370 baseHeaderName
.erase(0, 3);
371 for ( index
= 0; index
< WXSIZEOF(headers
); index
++ ) {
372 if ( Stricmp(baseHeaderName
, headers
[index
]) == 0 )
376 if ( (index
< WXSIZEOF(headers
)) && classes
[index
] ) {
377 // interesting header
378 interestingClasses
.Add(index
);
382 if ( !interestingClasses
.IsEmpty() ) {
383 // do generate "See also" clause
384 totalText
<< "\\wxheading{See also:}\n\n";
386 count
= interestingClasses
.Count();
387 for ( index
= 0; index
< count
; index
++ ) {
391 totalText
<< MakeHelpref(classes
[interestingClasses
[index
]]);
398 // the comment before the class generally explains what is it for so put it
399 // in place of the class description
400 if ( cl
.HasComments() ) {
401 wxString comment
= GetAllComments(cl
);
403 totalText
<< '\n' << comment
<< '\n';
406 // derived from section
407 wxString derived
= "\\wxheading{Derived from}\n\n";
409 const StrListT
& baseClasses
= cl
.mSuperClassNames
;
410 if ( baseClasses
.size() == 0 ) {
411 derived
<< "No base class";
415 for ( StrListT::const_iterator i
= baseClasses
.begin();
416 i
!= baseClasses
.end();
419 // separate from the previous one
426 wxString baseclass
= *i
;
427 derived
<< "\\helpref{" << baseclass
<< "}"
428 "{ " << baseclass
.MakeLower() << "}";
431 totalText
<< derived
<< "\n\n";
433 // write all this to file
434 m_file
.WriteTeX(totalText
);
436 // if there were any enums/typedefs before, insert their documentation now
437 InsertDataStructuresHeader();
442 void HelpGenVisitor::VisitEnumeration( spEnumeration
& en
)
446 if ( m_inMethodSection
) {
447 // FIXME that's a bug, but tell the user aboit it nevertheless... we
448 // should be smart enough to process even the enums which come after the
450 wxLogWarning("enum '%s' ignored, please put it before the class "
451 "methods.", en
.GetName().c_str());
455 // simply copy the enum text in the docs
456 wxString enumeration
= GetAllComments(en
);
457 enumeration
<< "{\\small \\begin{verbatim}\n"
459 << "\n\\end{verbatim}}\n";
461 // remember for later use if we're not inside a class yet
463 if ( !m_textStoredEnums
.IsEmpty() ) {
464 m_textStoredEnums
<< '\n';
467 m_textStoredEnums
<< enumeration
;
470 // write the header for this section if not done yet
471 InsertDataStructuresHeader();
474 m_file
.WriteTeX(enumeration
);
478 void HelpGenVisitor::VisitTypeDef( spTypeDef
& td
)
482 if ( m_inMethodSection
) {
483 // FIXME that's a bug, but tell the user aboit it nevertheless...
484 wxLogWarning("typedef '%s' ignored, please put it before the class "
485 "methods.", td
.GetName().c_str());
490 typedefdoc
<< "{\\small \\begin{verbatim}\n"
491 << "typedef " << td
.mOriginalType
<< ' ' << td
.GetName()
492 << "\n\\end{verbatim}}\n"
493 << GetAllComments(td
);
495 // remember for later use if we're not inside a class yet
497 if ( !m_textStoredTypedefs
.IsEmpty() ) {
498 m_textStoredTypedefs
<< '\n';
501 m_textStoredTypedefs
<< typedefdoc
;
504 // write the header for this section if not done yet
505 InsertDataStructuresHeader();
508 m_file
.WriteTeX(typedefdoc
);
512 void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine
& pd
)
514 switch ( pd
.GetStatementType() ) {
515 case SP_PREP_DEF_INCLUDE_FILE
:
516 m_headers
.Add(pd
.CPP_GetIncludedFileNeme());
519 case SP_PREP_DEF_DEFINE_SYMBOL
:
520 // TODO decide if it's a constant and document it if it is
525 void HelpGenVisitor::VisitAttribute( spAttribute
& attr
)
529 // only document the public member variables
530 if ( !m_inClass
|| !attr
.IsPublic() )
533 wxLogWarning("Ignoring member variable '%s'.", attr
.GetName().c_str());
536 void HelpGenVisitor::VisitOperation( spOperation
& op
)
540 if ( !m_inClass
|| !op
.IsInClass() ) {
541 // FIXME that's a bug too
542 wxLogWarning("skipped global function '%s'.", op
.GetName().c_str());
547 if ( op
.mVisibility
== SP_VIS_PRIVATE
) {
548 // FIXME should we document protected functions?
552 InsertMethodsHeader();
556 m_isFirstParam
= true;
558 m_textStoredFunctionComment
= GetAllComments(op
);
560 // start function documentation
562 const char *funcname
= op
.GetName().c_str();
563 const char *classname
= op
.GetClass().GetName().c_str();
565 // check for the special case of dtor
567 if ( (funcname
[0] == '~') && (strcmp(funcname
+ 1, classname
) == 0) ) {
568 dtor
.Printf("\\destruct{%s}", classname
);
572 totalText
.Printf("\\membersection{%s::%s}\\label{%s}\n"
573 "\\%sfunc{%s%s}{%s}{",
575 MakeLabel(classname
, funcname
).c_str(),
576 op
.mIsConstant
? "const" : "",
577 op
.mIsVirtual
? "virtual " : "",
581 m_file
.WriteTeX(totalText
);
584 void HelpGenVisitor::VisitParameter( spParameter
& param
)
590 if ( m_isFirstParam
) {
591 m_isFirstParam
= false;
597 totalText
<< "\\param{" << param
.mType
<< " }{" << param
.GetName();
598 wxString defvalue
= param
.mInitVal
;
599 if ( !defvalue
.IsEmpty() ) {
600 totalText
<< " = " << defvalue
;
605 m_file
.WriteTeX(totalText
);
608 // -----------------------------------------------------------------------------
609 // global function implementation
610 // -----------------------------------------------------------------------------
612 static wxString
MakeLabel(const char *classname
, const char *funcname
)
614 wxString
label(classname
);
615 if ( funcname
&& funcname
[0] == '\\' ) {
616 // we may have some special TeX macro - so far only \destruct exists,
617 // but may be later others will be added
618 static const char *macros
[] = { "destruct" };
619 static const char *replacement
[] = { "dtor" };
622 for ( n
= 0; n
< WXSIZEOF(macros
); n
++ ) {
623 if ( strncmp(funcname
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) {
629 if ( n
== WXSIZEOF(macros
) ) {
630 wxLogWarning("unknown function name '%s' - leaving as is.",
634 funcname
= replacement
[n
];
646 static wxString
MakeHelpref(const char *argument
)
649 helpref
<< "\\helpref{" << argument
<< "}{" << MakeLabel(argument
) << '}';
654 static void TeXFilter(wxString
* str
)
656 // FIXME may be done much more quickly
657 str
->Replace("&", "\\&");
658 str
->Replace("_", "\\_");
661 static wxString
GetAllComments(const spContext
& ctx
)
664 const MCommentListT
& comments
= ctx
.GetCommentList();
665 for ( MCommentListT::const_iterator i
= comments
.begin();
668 comment
<< (*i
)->GetText();
674 static const char *GetCurrentTime(const char *timeFormat
)
676 static char s_timeBuffer
[128];
681 ptmNow
= localtime(&timeNow
);
683 strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
);
688 /* vi: set tw=80 et ts=4 sw=4: */