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>
43 #include <wx/dynarray.h>
48 // C++ parsing classes
55 // -----------------------------------------------------------------------------
57 // -----------------------------------------------------------------------------
59 // return the label for the given function name (i.e. argument of \label)
60 static wxString
MakeLabel(const char *classname
, const char *funcname
= NULL
);
62 // return the whole \helpref{arg}{arg_label} string
63 static wxString
MakeHelpref(const char *argument
);
65 // quotes special TeX characters in place
66 static void TeXFilter(wxString
* str
);
68 // get all comments associated with this context
69 static wxString
GetAllComments(const spContext
& ctx
);
71 // get the string with current time (returns pointer to static buffer)
72 // timeFormat is used for the call of strftime(3)
77 static const char *GetCurrentTime(const char *timeFormat
);
79 // -----------------------------------------------------------------------------
81 // -----------------------------------------------------------------------------
83 // add a function which sanitazes the string before writing it to the file
84 class wxTeXFile
: public wxFile
87 wxTeXFile() : wxFile() { }
89 bool WriteTeX(const wxString
& s
)
94 return wxFile::Write(t
);
98 class HelpGenVisitor
: public spVisitor
104 virtual void VisitFile( spFile
& fl
);
105 virtual void VisitClass( spClass
& cl
);
106 virtual void VisitEnumeration( spEnumeration
& en
);
107 virtual void VisitTypeDef( spTypeDef
& td
);
108 virtual void VisitPreprocessorLine( spPreprocessorLine
& pd
);
109 virtual void VisitAttribute( spAttribute
& attr
);
110 virtual void VisitOperation( spOperation
& op
);
111 virtual void VisitParameter( spParameter
& param
);
115 // shut up g++ warning (ain't it stupid?)
116 virtual ~HelpGenVisitor() { }
119 // (re)initialize the state
122 // insert documentation for enums/typedefs coming immediately before the
123 // class declaration into the class documentation
124 void InsertTypedefDocs();
125 void InsertEnumDocs();
127 // write the headers for corresponding sections (only once)
128 void InsertDataStructuresHeader();
129 void InsertMethodsHeader();
131 // terminate the function documentation if it was started
132 void CloseFunction();
134 wxTeXFile m_file
; // file we're writing to now
137 bool m_inClass
, // TRUE after file successfully opened
138 m_inTypesSection
, // enums & typedefs go there
139 m_inMethodSection
, // functions go here
140 m_isFirstParam
, // first parameter of current function?
141 m_inFunction
; // we're parsing a function declaration
143 // holders for "saved" documentation
144 wxString m_textStoredEnums
,
145 m_textStoredTypedefs
,
146 m_textStoredFunctionComment
;
148 // headers included by this file
149 wxArrayString m_headers
;
152 // -----------------------------------------------------------------------------
154 // -----------------------------------------------------------------------------
156 // =============================================================================
158 // =============================================================================
160 // this function never returns
163 wxLogError("usage: HelpGen [-q|-v] <header files...>\n");
168 int main(int argc
, char **argv
)
175 for ( first
= 1; (first
< argc
) && argv
[first
][0] == '-'; first
++ ) {
176 switch ( argv
[first
][1] ) {
179 wxLog::GetActiveTarget()->SetVerbose();
184 wxLog::GetActiveTarget()->SetVerbose(false);
192 // create a parser object and a visitor derivation
193 CJSourceParser parser
;
194 HelpGenVisitor visitor
;
197 for ( int i
= first
; i
< argc
; i
++ ) {
198 spContext
*ctxTop
= parser
.ParseFile(argv
[i
]);
200 wxLogWarning("File '%s' couldn't be processed.", argv
[i
]);
203 ((spFile
*)ctxTop
)->mFileName
= argv
[i
];
204 visitor
.VisitAll(*ctxTop
);
212 // -----------------------------------------------------------------------------
213 // HelpGenVisitor implementation
214 // -----------------------------------------------------------------------------
216 HelpGenVisitor::HelpGenVisitor()
221 void HelpGenVisitor::Reset()
226 m_inMethodSection
= false;
228 m_textStoredTypedefs
=
230 m_textStoredFunctionComment
= "";
234 void HelpGenVisitor::InsertTypedefDocs()
236 m_file
.WriteTeX(m_textStoredTypedefs
);
237 m_textStoredTypedefs
.Empty();
240 void HelpGenVisitor::InsertEnumDocs()
242 m_file
.WriteTeX(m_textStoredEnums
);
243 m_textStoredEnums
.Empty();
246 void HelpGenVisitor::InsertDataStructuresHeader()
248 if ( !m_inTypesSection
) {
249 m_inTypesSection
= true;
251 m_file
.WriteTeX("\\wxheading{Data structures}\n\n");
255 void HelpGenVisitor::InsertMethodsHeader()
257 if ( !m_inMethodSection
) {
258 m_inMethodSection
= true;
260 m_file
.WriteTeX( "\\latexignore{\\rtfignore{\\wxheading{Members}}}\n\n");
264 void HelpGenVisitor::CloseFunction()
266 if ( m_inFunction
) {
267 m_inFunction
= false;
270 if ( m_isFirstParam
) {
272 totalText
<< "\\void";
275 totalText
<< "}\n\n";
277 if ( !m_textStoredFunctionComment
.IsEmpty() )
278 totalText
<< m_textStoredFunctionComment
<< '\n';
280 m_file
.WriteTeX(totalText
);
284 void HelpGenVisitor::EndVisit()
288 wxLogInfo("%s: finished parsing the current file.",
289 GetCurrentTime("%H:%M:%S"));
292 void HelpGenVisitor::VisitFile( spFile
& file
)
294 wxLogInfo("%s: started to parse classes from file '%s'...",
295 GetCurrentTime("%H:%M:%S"), file
.mFileName
.c_str());
298 void HelpGenVisitor::VisitClass( spClass
& cl
)
300 wxString name
= cl
.GetName();
302 // the file name is built from the class name by removing the leading "wx"
303 // if any and converting it to the lower case
304 wxString filename
= name
;
305 if ( filename(0, 2) == "wx" ) {
306 filename
.erase(0, 2);
309 filename
.MakeLower();
312 m_inClass
= m_file
.Open(filename
, wxFile::write
);
314 wxLogError("Can't generate documentation for the class '%s'.",
321 m_inTypesSection
= false;
323 wxLogInfo("Created new file '%s' for class '%s'.",
324 filename
.c_str(), name
.c_str());
326 // the entire text we're writing to file
329 // write out the header
332 header
.Printf("% automatically generated by HelpGen from %s at %s\n"
333 "\\section{\\class{%s}}\\label{%s}\n",
334 filename
.c_str(), GetCurrentTime("%d/%b/%y %H:%M:%S"),
335 name
.c_str(), wxString(name
).MakeLower().c_str());
337 totalText
<< header
<< '\n';
340 // if the header includes other headers they must be related to it... try to
341 // automatically generate the "See also" clause
342 if ( !m_headers
.IsEmpty() ) {
343 // correspondence between wxWindows headers and class names
344 static const char *headers
[] = {
353 // NULL here means not to insert anything in "See also" for the
354 // corresponding header
355 static const char *classes
[] = {
364 wxASSERT_MSG( WXSIZEOF(headers
) == WXSIZEOF(classes
),
365 "arrays must be in sync!" );
367 wxArrayInt interestingClasses
;
369 size_t count
= m_headers
.Count(), index
;
370 for ( size_t n
= 0; n
< count
; n
++ ) {
371 wxString baseHeaderName
= m_headers
[n
].Before('.');
372 if ( baseHeaderName(0, 3) != "wx/" )
375 baseHeaderName
.erase(0, 3);
376 for ( index
= 0; index
< WXSIZEOF(headers
); index
++ ) {
377 if ( Stricmp(baseHeaderName
, headers
[index
]) == 0 )
381 if ( (index
< WXSIZEOF(headers
)) && classes
[index
] ) {
382 // interesting header
383 interestingClasses
.Add(index
);
387 if ( !interestingClasses
.IsEmpty() ) {
388 // do generate "See also" clause
389 totalText
<< "\\wxheading{See also:}\n\n";
391 count
= interestingClasses
.Count();
392 for ( index
= 0; index
< count
; index
++ ) {
396 totalText
<< MakeHelpref(classes
[interestingClasses
[index
]]);
403 // the comment before the class generally explains what is it for so put it
404 // in place of the class description
405 if ( cl
.HasComments() ) {
406 wxString comment
= GetAllComments(cl
);
408 totalText
<< '\n' << comment
<< '\n';
411 // derived from section
412 wxString derived
= "\\wxheading{Derived from}\n\n";
414 const StrListT
& baseClasses
= cl
.mSuperClassNames
;
415 if ( baseClasses
.size() == 0 ) {
416 derived
<< "No base class";
420 for ( StrListT::const_iterator i
= baseClasses
.begin();
421 i
!= baseClasses
.end();
424 // separate from the previous one
431 wxString baseclass
= *i
;
432 derived
<< "\\helpref{" << baseclass
<< "}"
433 "{ " << baseclass
.MakeLower() << "}";
436 totalText
<< derived
<< "\n\n";
438 // write all this to file
439 m_file
.WriteTeX(totalText
);
441 // if there were any enums/typedefs before, insert their documentation now
442 InsertDataStructuresHeader();
447 void HelpGenVisitor::VisitEnumeration( spEnumeration
& en
)
451 if ( m_inMethodSection
) {
452 // FIXME that's a bug, but tell the user aboit it nevertheless... we
453 // should be smart enough to process even the enums which come after the
455 wxLogWarning("enum '%s' ignored, please put it before the class "
456 "methods.", en
.GetName().c_str());
460 // simply copy the enum text in the docs
461 wxString enumeration
= GetAllComments(en
);
462 enumeration
<< "{\\small \\begin{verbatim}\n"
464 << "\n\\end{verbatim}}\n";
466 // remember for later use if we're not inside a class yet
468 if ( !m_textStoredEnums
.IsEmpty() ) {
469 m_textStoredEnums
<< '\n';
472 m_textStoredEnums
<< enumeration
;
475 // write the header for this section if not done yet
476 InsertDataStructuresHeader();
479 m_file
.WriteTeX(enumeration
);
483 void HelpGenVisitor::VisitTypeDef( spTypeDef
& td
)
487 if ( m_inMethodSection
) {
488 // FIXME that's a bug, but tell the user aboit it nevertheless...
489 wxLogWarning("typedef '%s' ignored, please put it before the class "
490 "methods.", td
.GetName().c_str());
495 typedefdoc
<< "{\\small \\begin{verbatim}\n"
496 << "typedef " << td
.mOriginalType
<< ' ' << td
.GetName()
497 << "\n\\end{verbatim}}\n"
498 << GetAllComments(td
);
500 // remember for later use if we're not inside a class yet
502 if ( !m_textStoredTypedefs
.IsEmpty() ) {
503 m_textStoredTypedefs
<< '\n';
506 m_textStoredTypedefs
<< typedefdoc
;
509 // write the header for this section if not done yet
510 InsertDataStructuresHeader();
513 m_file
.WriteTeX(typedefdoc
);
517 void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine
& pd
)
519 switch ( pd
.GetStatementType() ) {
520 case SP_PREP_DEF_INCLUDE_FILE
:
521 m_headers
.Add(pd
.CPP_GetIncludedFileNeme());
524 case SP_PREP_DEF_DEFINE_SYMBOL
:
525 // TODO decide if it's a constant and document it if it is
530 void HelpGenVisitor::VisitAttribute( spAttribute
& attr
)
534 // only document the public member variables
535 if ( !m_inClass
|| !attr
.IsPublic() )
538 wxLogWarning("Ignoring member variable '%s'.", attr
.GetName().c_str());
541 void HelpGenVisitor::VisitOperation( spOperation
& op
)
545 if ( !m_inClass
|| !op
.IsInClass() ) {
546 // FIXME that's a bug too
547 wxLogWarning("skipped global function '%s'.", op
.GetName().c_str());
552 if ( op
.mVisibility
== SP_VIS_PRIVATE
) {
553 // FIXME should we document protected functions?
557 InsertMethodsHeader();
561 m_isFirstParam
= true;
563 m_textStoredFunctionComment
= GetAllComments(op
);
565 // start function documentation
567 const char *funcname
= op
.GetName().c_str();
568 const char *classname
= op
.GetClass().GetName().c_str();
570 // check for the special case of dtor
572 if ( (funcname
[0] == '~') && (strcmp(funcname
+ 1, classname
) == 0) ) {
573 dtor
.Printf("\\destruct{%s}", classname
);
577 totalText
.Printf("\\membersection{%s::%s}\\label{%s}\n"
578 "\\%sfunc{%s%s}{%s}{",
580 MakeLabel(classname
, funcname
).c_str(),
581 op
.mIsConstant
? "const" : "",
582 op
.mIsVirtual
? "virtual " : "",
586 m_file
.WriteTeX(totalText
);
589 void HelpGenVisitor::VisitParameter( spParameter
& param
)
595 if ( m_isFirstParam
) {
596 m_isFirstParam
= false;
602 totalText
<< "\\param{" << param
.mType
<< " }{" << param
.GetName();
603 wxString defvalue
= param
.mInitVal
;
604 if ( !defvalue
.IsEmpty() ) {
605 totalText
<< " = " << defvalue
;
610 m_file
.WriteTeX(totalText
);
613 // -----------------------------------------------------------------------------
614 // global function implementation
615 // -----------------------------------------------------------------------------
617 static wxString
MakeLabel(const char *classname
, const char *funcname
)
619 wxString
label(classname
);
620 if ( funcname
&& funcname
[0] == '\\' ) {
621 // we may have some special TeX macro - so far only \destruct exists,
622 // but may be later others will be added
623 static const char *macros
[] = { "destruct" };
624 static const char *replacement
[] = { "dtor" };
627 for ( n
= 0; n
< WXSIZEOF(macros
); n
++ ) {
628 if ( strncmp(funcname
+ 1, macros
[n
], strlen(macros
[n
])) == 0 ) {
634 if ( n
== WXSIZEOF(macros
) ) {
635 wxLogWarning("unknown function name '%s' - leaving as is.",
639 funcname
= replacement
[n
];
651 static wxString
MakeHelpref(const char *argument
)
654 helpref
<< "\\helpref{" << argument
<< "}{" << MakeLabel(argument
) << '}';
659 static void TeXFilter(wxString
* str
)
661 // FIXME may be done much more quickly
662 str
->Replace("&", "\\&");
663 str
->Replace("_", "\\_");
666 static wxString
GetAllComments(const spContext
& ctx
)
669 const MCommentListT
& comments
= ctx
.GetCommentList();
670 for ( MCommentListT::const_iterator i
= comments
.begin();
673 comment
<< (*i
)->GetText();
679 static const char *GetCurrentTime(const char *timeFormat
)
681 static char s_timeBuffer
[128];
686 ptmNow
= localtime(&timeNow
);
688 strftime(s_timeBuffer
, WXSIZEOF(s_timeBuffer
), timeFormat
, ptmNow
);
693 /* vi: set tw=80 et ts=4 sw=4: */