X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/cecfc5e7e54067ea099334a1fbce852ca69a6b11..fed485e0946d9cff74fce6afdb169796d90a99f2:/utils/HelpGen/src/HelpGen.cpp diff --git a/utils/HelpGen/src/HelpGen.cpp b/utils/HelpGen/src/HelpGen.cpp index af3023ecdf..28f36a2f01 100644 --- a/utils/HelpGen/src/HelpGen.cpp +++ b/utils/HelpGen/src/HelpGen.cpp @@ -18,9 +18,11 @@ 2. Document typedefs 3. Document global variables 4. Document #defines + +5. Program options (ii) plans for version 2 1. Use wxTextFile for direct file access to avoid one scan method problems + 2. Use command line parsrer class for the options */ @@ -38,9 +40,11 @@ #ifndef WX_PRECOMP #include #include - #include + #include #endif // WX_PRECOMP +#include + // C++ parsing classes #include "cjparser.h" @@ -52,12 +56,26 @@ // private functions // ----------------------------------------------------------------------------- -// return the label for the given function name -static wxString MakeLabel(const char *classname, const char *funcname); - +// return the label for the given function name (i.e. argument of \label) +static wxString MakeLabel(const char *classname, const char *funcname = NULL); + +// return the whole \helpref{arg}{arg_label} string +static wxString MakeHelpref(const char *argument); + // quotes special TeX characters in place static void TeXFilter(wxString* str); +// get all comments associated with this context +static wxString GetAllComments(const spContext& ctx); + +// get the string with current time (returns pointer to static buffer) +// timeFormat is used for the call of strftime(3) +#ifdef GetCurrentTime +#undef GetCurrentTime +#endif + +static const char *GetCurrentTime(const char *timeFormat); + // ----------------------------------------------------------------------------- // private classes // ----------------------------------------------------------------------------- @@ -87,6 +105,7 @@ public: virtual void VisitClass( spClass& cl ); virtual void VisitEnumeration( spEnumeration& en ); virtual void VisitTypeDef( spTypeDef& td ); + virtual void VisitPreprocessorLine( spPreprocessorLine& pd ); virtual void VisitAttribute( spAttribute& attr ); virtual void VisitOperation( spOperation& op ); virtual void VisitParameter( spParameter& param ); @@ -125,6 +144,9 @@ protected: wxString m_textStoredEnums, m_textStoredTypedefs, m_textStoredFunctionComment; + + // headers included by this file + wxArrayString m_headers; }; // ----------------------------------------------------------------------------- @@ -135,23 +157,44 @@ protected: // implementation // ============================================================================= +// this function never returns +static void usage() +{ + wxLogError("usage: HelpGen [-q|-v]
\n"); + + exit(1); +} + int main(int argc, char **argv) { if ( argc < 2 ) { - wxLogError("usage: %s
\n", argv[0]); - - return 1; + usage(); } - // be verbose - wxLog::GetActiveTarget()->SetVerbose(); + int first; + for ( first = 1; (first < argc) && argv[first][0] == '-'; first++ ) { + switch ( argv[first][1] ) { + case 'v': + // be verbose + wxLog::GetActiveTarget()->SetVerbose(); + break; + + case 'q': + // be quiet + wxLog::GetActiveTarget()->SetVerbose(false); + break; + + default: + usage(); + } + } // create a parser object and a visitor derivation CJSourceParser parser; HelpGenVisitor visitor; // parse all files - for ( int i = 1; i < argc; i++ ) { + for ( int i = first; i < argc; i++ ) { spContext *ctxTop = parser.ParseFile(argv[i]); if ( !ctxTop ) { wxLogWarning("File '%s' couldn't be processed.", argv[i]); @@ -181,6 +224,11 @@ void HelpGenVisitor::Reset() m_inFunction = m_inTypesSection = m_inMethodSection = false; + + m_textStoredTypedefs = + m_textStoredEnums = + m_textStoredFunctionComment = ""; + m_headers.Empty(); } void HelpGenVisitor::InsertTypedefDocs() @@ -236,11 +284,15 @@ void HelpGenVisitor::CloseFunction() void HelpGenVisitor::EndVisit() { CloseFunction(); + + wxLogInfo("%s: finished parsing the current file.", + GetCurrentTime("%H:%M:%S")); } void HelpGenVisitor::VisitFile( spFile& file ) { - wxLogInfo("Parsing classes from file '%s'...", file.mFileName.c_str()); + wxLogInfo("%s: started to parse classes from file '%s'...", + GetCurrentTime("%H:%M:%S"), file.mFileName.c_str()); } void HelpGenVisitor::VisitClass( spClass& cl ) @@ -276,27 +328,82 @@ void HelpGenVisitor::VisitClass( spClass& cl ) // write out the header { - time_t timeNow = time(NULL); wxString header; - header.Printf("% automatically generated by HelpGen from %s at " - "%s" // no '\n' here because ctime() inserts one + header.Printf("% automatically generated by HelpGen from %s at %s\n" "\\section{\\class{%s}}\\label{%s}\n", - filename.c_str(), ctime(&timeNow), + filename.c_str(), GetCurrentTime("%d/%b/%y %H:%M:%S"), name.c_str(), wxString(name).MakeLower().c_str()); totalText << header << '\n'; } + // if the header includes other headers they must be related to it... try to + // automatically generate the "See also" clause + if ( !m_headers.IsEmpty() ) { + // correspondence between wxWindows headers and class names + static const char *headers[] = { + "object", + "defs", + "string", + "dynarray", + "file", + "time", + }; + + // NULL here means not to insert anything in "See also" for the + // corresponding header + static const char *classes[] = { + NULL, + NULL, + NULL, + NULL, + "wxFile", + "wxTime", + }; + + wxASSERT_MSG( WXSIZEOF(headers) == WXSIZEOF(classes), + "arrays must be in sync!" ); + + wxArrayInt interestingClasses; + + size_t count = m_headers.Count(), index; + for ( size_t n = 0; n < count; n++ ) { + wxString baseHeaderName = m_headers[n].Before('.'); + if ( baseHeaderName(0, 3) != "wx/" ) + continue; + + baseHeaderName.erase(0, 3); + for ( index = 0; index < WXSIZEOF(headers); index++ ) { + if ( Stricmp(baseHeaderName, headers[index]) == 0 ) + break; + } + + if ( (index < WXSIZEOF(headers)) && classes[index] ) { + // interesting header + interestingClasses.Add(index); + } + } + + if ( !interestingClasses.IsEmpty() ) { + // do generate "See also" clause + totalText << "\\wxheading{See also:}\n\n"; + + count = interestingClasses.Count(); + for ( index = 0; index < count; index++ ) { + if ( index > 0 ) + totalText << ", "; + + totalText << MakeHelpref(classes[interestingClasses[index]]); + } + + totalText << "\n\n"; + } + } + // the comment before the class generally explains what is it for so put it // in place of the class description if ( cl.HasComments() ) { - wxString comment; - const MCommentListT& comments = cl.GetCommentList(); - for ( MCommentListT::const_iterator i = comments.begin(); - i != comments.end(); - i++ ) { - comment << (*i)->GetText(); - } + wxString comment = GetAllComments(cl); totalText << '\n' << comment << '\n'; } @@ -322,8 +429,8 @@ void HelpGenVisitor::VisitClass( spClass& cl ) } wxString baseclass = *i; - derived << "\\helpref{" << baseclass << "}" - "{ " << baseclass.MakeLower() << "}"; + derived << "\\helpref{" << baseclass << "}"; + derived << "{" << baseclass.MakeLower() << "}"; } } totalText << derived << "\n\n"; @@ -351,7 +458,7 @@ void HelpGenVisitor::VisitEnumeration( spEnumeration& en ) } // simply copy the enum text in the docs - wxString enumeration; + wxString enumeration = GetAllComments(en); enumeration << "{\\small \\begin{verbatim}\n" << en.mEnumContent << "\n\\end{verbatim}}\n"; @@ -377,7 +484,47 @@ void HelpGenVisitor::VisitTypeDef( spTypeDef& td ) { CloseFunction(); - wxFAIL_MSG("don't know how to document typedefs yet"); + if ( m_inMethodSection ) { + // FIXME that's a bug, but tell the user aboit it nevertheless... + wxLogWarning("typedef '%s' ignored, please put it before the class " + "methods.", td.GetName().c_str()); + return; + } + + wxString typedefdoc; + typedefdoc << "{\\small \\begin{verbatim}\n" + << "typedef " << td.mOriginalType << ' ' << td.GetName() + << "\n\\end{verbatim}}\n" + << GetAllComments(td); + + // remember for later use if we're not inside a class yet + if ( !m_inClass ) { + if ( !m_textStoredTypedefs.IsEmpty() ) { + m_textStoredTypedefs << '\n'; + } + + m_textStoredTypedefs << typedefdoc; + } + else { + // write the header for this section if not done yet + InsertDataStructuresHeader(); + + typedefdoc << '\n'; + m_file.WriteTeX(typedefdoc); + } +} + +void HelpGenVisitor::VisitPreprocessorLine( spPreprocessorLine& pd ) +{ + switch ( pd.GetStatementType() ) { + case SP_PREP_DEF_INCLUDE_FILE: + m_headers.Add(pd.CPP_GetIncludedFileNeme()); + break; + + case SP_PREP_DEF_DEFINE_SYMBOL: + // TODO decide if it's a constant and document it if it is + break; + } } void HelpGenVisitor::VisitAttribute( spAttribute& attr ) @@ -388,7 +535,7 @@ void HelpGenVisitor::VisitAttribute( spAttribute& attr ) if ( !m_inClass || !attr.IsPublic() ) return; - wxFAIL_MSG("don't know how to document member vars yet"); + wxLogWarning("Ignoring member variable '%s'.", attr.GetName().c_str()); } void HelpGenVisitor::VisitOperation( spOperation& op ) @@ -413,13 +560,7 @@ void HelpGenVisitor::VisitOperation( spOperation& op ) m_inFunction = m_isFirstParam = true; - m_textStoredFunctionComment.Empty(); - const MCommentListT& comments = op.GetCommentList(); - for ( MCommentListT::const_iterator i = comments.begin(); - i != comments.end(); - i++ ) { - m_textStoredFunctionComment << (*i)->GetText(); - } + m_textStoredFunctionComment = GetAllComments(op); // start function documentation wxString totalText; @@ -433,11 +574,12 @@ void HelpGenVisitor::VisitOperation( spOperation& op ) funcname = dtor; } - totalText.Printf("\\membersection{%s::%s}\\label{%s}\n" - "\\%sfunc{%s}{%s}{", + totalText.Printf("\\membersection{%s::%s}\\label{%s}\n\n" + "\\%sfunc{%s%s}{%s}{", classname, funcname, MakeLabel(classname, funcname).c_str(), op.mIsConstant ? "const" : "", + op.mIsVirtual ? "virtual " : "", op.mRetType.c_str(), funcname); @@ -475,7 +617,7 @@ void HelpGenVisitor::VisitParameter( spParameter& param ) static wxString MakeLabel(const char *classname, const char *funcname) { wxString label(classname); - if ( funcname[0] == '\\' ) { + if ( funcname && funcname[0] == '\\' ) { // we may have some special TeX macro - so far only \destruct exists, // but may be later others will be added static const char *macros[] = { "destruct" }; @@ -498,13 +640,22 @@ static wxString MakeLabel(const char *classname, const char *funcname) } } - label << funcname; + if ( funcname ) + label << funcname; label.MakeLower(); return label; } +static wxString MakeHelpref(const char *argument) +{ + wxString helpref; + helpref << "\\helpref{" << argument << "}{" << MakeLabel(argument) << '}'; + + return helpref; +} + static void TeXFilter(wxString* str) { // FIXME may be done much more quickly @@ -512,4 +663,31 @@ static void TeXFilter(wxString* str) str->Replace("_", "\\_"); } +static wxString GetAllComments(const spContext& ctx) +{ + wxString comment; + const MCommentListT& comments = ctx.GetCommentList(); + for ( MCommentListT::const_iterator i = comments.begin(); + i != comments.end(); + i++ ) { + comment << (*i)->GetText(); + } + + return comment; +} + +static const char *GetCurrentTime(const char *timeFormat) +{ + static char s_timeBuffer[128]; + time_t timeNow; + struct tm *ptmNow; + + time(&timeNow); + ptmNow = localtime(&timeNow); + + strftime(s_timeBuffer, WXSIZEOF(s_timeBuffer), timeFormat, ptmNow); + + return s_timeBuffer; +} + /* vi: set tw=80 et ts=4 sw=4: */