///////////////////////////////////////////////////////////////////////////// // Name: No names yet. // Purpose: Contrib. demo // Author: Aleksandras Gluchovas // Modified by: // Created: 22/09/98 // RCS-ID: $Id: docripper.cpp 34519 2005-06-02 09:44:45Z ABX $ // Copyright: (c) Aleskandars Gluchovas // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/wx.h" #endif #include "docripper.h" #if wxUSE_IOSTREAMH #include #else #include #endif // script templates // ***** currently only HTML versions of variouse templates available ***** // static const char* HTM_TopTempl = "\n\ \n\n\n\n\n\

$(NAME)

\n\

\n\n\ "; static const char* HTM_ContentIdxTempl = "\ \n\


\n\

$(NAME)

\
    \n\ $(REFLIST)\

\n\n\ "; static const char* HTM_SuperContentTempl = "\ \n\


\n\

$(NAME)

\ $(BODY)\n\ "; static const char* HTM_SubContentTempl = "\
\n\


\n\

$(NAME)

\ $(BODY)\n\ "; static const char* HTM_OutLineTempl = "\

\n\ $(NAME)

\n\ "; static const char* HTM_OutLine1Templ = "\

\n\ $(NAME)\n\

    \n\ $(REFLIST)\
\n\n\ "; static const char* HTM_RefTempl = "\
  • $(NAME)\n\ "; static const char* HTM_DeadRefTempl = "\
  • $(NAME)\n\ "; /***** Implementation for class RipperDocGen *****/ RipperDocGen::RipperDocGen() : mTopTempl ( HTM_TopTempl ), mContentIdxTempl ( HTM_ContentIdxTempl ), mSuperContentTempl( HTM_SuperContentTempl ), mSubContentTempl ( HTM_SubContentTempl ), mOutLineTempl ( HTM_OutLineTempl ), mOutLine1Templ ( HTM_OutLine1Templ ), mRefTempl ( HTM_RefTempl ), mDeadRefTempl ( HTM_DeadRefTempl ), mpCurClassSect(0) { // topIndex is not referenced mpTopIdx = new ScriptSection( "Source Code Contents" , wxEmptyString, &mTopTempl , 0 ); mpClassIdx = new ScriptSection( "Classes Reference" , wxEmptyString, &mContentIdxTempl, &mRefTempl ); mpEnumIdx = new ScriptSection( "Enumerations Reference" , wxEmptyString, &mContentIdxTempl, &mRefTempl ); mpTypeDefIdx = new ScriptSection( "Type Definitions Reference" , wxEmptyString, &mContentIdxTempl, &mRefTempl ); mpMacroIdx = new ScriptSection( "Macros Reference" , wxEmptyString, &mContentIdxTempl, &mRefTempl ); mpGlobalVarsIdx = new ScriptSection( "Global Variables Reference" , wxEmptyString, &mContentIdxTempl, &mRefTempl ); mpGlobalFuncIdx = new ScriptSection( "Global Functions Reference", wxEmptyString, &mContentIdxTempl, &mRefTempl ); mpConstIdx = new ScriptSection( "Constants Reference" , wxEmptyString, &mContentIdxTempl, &mRefTempl ); // assemble top index mpTopIdx->AddSection( mpClassIdx , 1 ); mpTopIdx->AddSection( mpEnumIdx , 1 ); mpTopIdx->AddSection( mpTypeDefIdx , 1 ); mpTopIdx->AddSection( mpMacroIdx , 1 ); mpTopIdx->AddSection( mpGlobalVarsIdx, 1 ); mpTopIdx->AddSection( mpGlobalFuncIdx, 1 ); mpTopIdx->AddSection( mpConstIdx , 1 ); // register reserved variables for index and description templates ScriptSection::RegisterTemplate( mTopTempl ); ScriptSection::RegisterTemplate( mContentIdxTempl ); ScriptSection::RegisterTemplate( mSuperContentTempl ); ScriptSection::RegisterTemplate( mSubContentTempl ); ScriptSection::RegisterTemplate( mOutLineTempl ); ScriptSection::RegisterTemplate( mOutLine1Templ ); ScriptSection::RegisterTemplate( mRefTempl ); ScriptSection::RegisterTemplate( mDeadRefTempl ); // create the top-most (interfile) context mpFileBinderCtx = new spFile(); // the default script is HTML m_Tags = get_HTML_markup_tags(); mpParser = 0; // no default parser! } void RipperDocGen::Init( SourceParserBase* pParser ) { mpParser = pParser; } RipperDocGen::~RipperDocGen() { delete mpFileBinderCtx; } void RipperDocGen::AppendComments( spContext& fromContext, wxString& str ) { if ( !fromContext.HasComments() ) return; size_t start = str.length(); str += m_Tags[TAG_BOLD].end; str += m_Tags[TAG_PARAGRAPH].start; MCommentListT& lst = fromContext.GetCommentList(); for( size_t i = 0; i != lst.size(); ++i ) { if ( i != 0 ) if ( lst[i]->StartsParagraph() ) { str += m_Tags[TAG_PARAGRAPH].start; } str += lst[i]->m_Text; } // remove new lines, and insert paragraph breaks // if empty lines found size_t len = str.length(); for( size_t n = start; n != len; ++n ) if ( str[n] == 10 || str[n] == 13 ) { if ( n + 2 < len ) { if ( ( str[n] == 13 && str[n+1] == 10 && // FIXME:: quick-hack str[n+2] == 13 ) || ( str[n] == 10 && str[n+1] == 10 ) ) { str.insert( n + 1, _T("

    ") ); // FIXME:: quick-hack len += 3; } } str[n] = _T(' '); } str += m_Tags[TAG_PARAGRAPH].end; } void RipperDocGen::AppendMulitilineStr( wxString& st, wxString& mlStr ) { st = m_Tags[TAG_FIXED_FONT].start; st += mlStr; st += m_Tags[TAG_FIXED_FONT].end; } void RipperDocGen::AppendHighlightedSource( wxString& st, wxString source ) { // FIXME:: below should not be fixed :) wxChar buf[1024*32]; // DBG::: // ASSERT( source.length() + 1 < sizeof(buf) ); wxStrcpy( buf, source.c_str() ); // highlight things mSrcPainter.Init(); mSrcPainter.ProcessSource( buf, strlen(buf) ); mSrcPainter.GetResultString( st, m_Tags ); } bool RipperDocGen::CheckIfUncommented( spContext& ctx, ScriptSection& toSect ) { if ( ctx.HasComments() ) return 0; toSect.AddReference( new ScriptSection( GetScopedName( ctx ), wxEmptyString, 0, &mDeadRefTempl ) ); return 1; } ScriptTemplate* RipperDocGen::GetRefTemplFor( spContext& ctx ) { if ( ctx.HasComments() ) return &mRefTempl; else return &mDeadRefTempl; } wxString RipperDocGen::GetScopedName( spContext& ofCtx ) { if ( ofCtx.IsInFile() ) return ofCtx.GetName(); else return ofCtx.GetOutterContext()->GetName() + _T("::") + ofCtx.GetName(); } void RipperDocGen::AddToCurrentClass( ScriptSection* pSection, spContext& ctx, const char* subSectionName ) { wxString sName; if ( ctx.mVisibility == SP_VIS_PROTECTED ) sName = "Protected members/"; else if ( ctx.mVisibility == SP_VIS_PRIVATE ) sName = "Private members/"; else sName = "Public members/"; sName += subSectionName; ScriptSection* pSect = mpCurClassSect->GetSubsection( sName.c_str() ); if ( CheckIfUncommented( ctx, *pSect ) ) { delete pSection; return; } pSect->AddReference( pSection ); mpCurClassSect->AddSection( pSection ); } void RipperDocGen::LinkSuperClassRefs() { MMemberListT clLst; // collect all classes in the context tree mpFileBinderCtx->GetContextList( clLst, SP_CTX_CLASS ); for( size_t i = 0; i != clLst.size(); ++i ) { spClass& cl = *((spClass*)clLst[i]); // FIXME:: why sometimes GetUserData() returns NULL? if ( !cl.GetUserData() ) continue; ScriptSection* pClSect = (ScriptSection*)cl.GetUserData(); ScriptSection* pSuperSect = pClSect->GetSubsection("Derived from"); for( size_t n = 0; n != cl.m_SuperClassNames.size(); ++n ) { wxString& superClName = cl.m_SuperClassNames[n]; spClass* pFound = NULL; for( size_t k = 0; k != clLst.size(); ++k ) { if ( clLst[k]->GetName() == superClName ) { pFound = (spClass*)clLst[k]; break; } } if ( !pFound ) { ScriptSection* pNotFound = new ScriptSection( superClName, wxEmptyString, 0, &mDeadRefTempl ); pSuperSect->AddReference( pNotFound ); } else if ( pFound->GetUserData() ) pSuperSect->AddReference( (ScriptSection*)pFound->GetUserData() ); } } } void RipperDocGen::ProcessFile( const char* sourceFile ) { wxSTD cout << "Processing file " << sourceFile << "..." << wxSTD endl; spFile* pCtx = mpParser->ParseFile( sourceFile ); if ( pCtx == NULL ) { wxSTD cout << "Cannot open file " << sourceFile << ", skipped..." << wxSTD endl; return; } VisitAll( *pCtx, true ); mpFileBinderCtx->AddMember( pCtx ); } // implementations of "visiting procedures" void RipperDocGen::VisitEnumeration( spEnumeration& en ) { // FOR NOW:: do not reference "nameless" enums if ( en.GetName().empty() ) return; if ( CheckIfUncommented( en, *mpEnumIdx ) ) return; wxString body; body += m_Tags[TAG_BOLD].start; AppendMulitilineStr( body, en.m_EnumContent ); body += m_Tags[TAG_BOLD].end; wxString line; AppendHighlightedSource( line, body ); AppendComments( en, line ); mpEnumIdx->AddSection( new ScriptSection( en.GetName(), line, &mSubContentTempl, GetRefTemplFor( en ) ), 1 ); } void RipperDocGen::VisitTypeDef( spTypeDef& td ) { if ( CheckIfUncommented( td, *mpTypeDefIdx ) ) return; wxString body; body += m_Tags[TAG_BOLD].start; body += "typdef "; body += m_Tags[TAG_BOLD].end; AppendMulitilineStr( body, td.m_OriginalType ); body += td.m_OriginalType; body += ' '; body += m_Tags[TAG_BOLD].start; body += td.GetName(); body += m_Tags[TAG_BOLD].end; wxString line; AppendHighlightedSource( line, body ); AppendComments( td, line ); mpTypeDefIdx->AddSection( new ScriptSection( td.GetName(), line, &mSubContentTempl, GetRefTemplFor( td ) ), true ); } void RipperDocGen::VisitPreprocessorLine( spPreprocessorLine& pd ) { if ( pd.mDefType != SP_PREP_DEF_REDEFINE_SYMBOL ) return; if ( CheckIfUncommented( pd, *mpMacroIdx ) ) return; wxString body; body += m_Tags[TAG_FIXED_FONT].start; wxString coloredLine = pd.m_Line; AppendHighlightedSource( coloredLine, pd.m_Line ); AppendMulitilineStr( body, coloredLine ); body += m_Tags[TAG_FIXED_FONT].end; AppendComments( pd, body ); mpMacroIdx->AddSection( new ScriptSection( pd.GetName(), body, &mSubContentTempl, GetRefTemplFor( pd ) ), true ); } void RipperDocGen::VisitClass( spClass& cl ) { // FOR NOW:: do not document nested classes - // nicier visiting method yet needed if ( cl.IsInClass() ) { SkipChildren(); // spVisitor's method return; } wxString body; AppendComments( cl, body ); mpCurClassSect = new ScriptSection( cl.GetName(), body, &mSuperContentTempl, &mRefTempl ); // set up reference in the class context, pointing back // to the section where this class is represented cl.SetUserData( mpCurClassSect ); ScriptSection* pSuper = new ScriptSection( "Derived from" ,wxEmptyString, &mOutLine1Templ,0, 1 ); ScriptSection* pPublic = new ScriptSection( "Public members" ,wxEmptyString, &mOutLineTempl,0, 1 ); ScriptSection* pProtected = new ScriptSection( "Protected members" ,wxEmptyString, &mOutLineTempl,0, 1 ); ScriptSection* pPrivate = new ScriptSection( "Private members" ,wxEmptyString, &mOutLineTempl,0, 1 ); pPublic->AddSection( new ScriptSection( "Operations", wxEmptyString, &mOutLine1Templ, 0, 1 ) ); pPublic->AddSection( new ScriptSection( "Attributes", wxEmptyString, &mOutLine1Templ, 0, 1 ) ); pProtected->AddSection( new ScriptSection( "Operations", wxEmptyString, &mOutLine1Templ, 0, 1 ) ); pProtected->AddSection( new ScriptSection( "Attributes", wxEmptyString, &mOutLine1Templ, 0, 1 ) ); pPrivate->AddSection( new ScriptSection( "Operations", wxEmptyString, &mOutLine1Templ, 0, 1 ) ); pPrivate->AddSection( new ScriptSection( "Attributes", wxEmptyString, &mOutLine1Templ, 0, 1 ) ); mpCurClassSect->AddSection( pSuper ); mpCurClassSect->AddSection( pPublic ); mpCurClassSect->AddSection( pProtected ); mpCurClassSect->AddSection( pPrivate ); mpClassIdx->AddSection( mpCurClassSect, true ); } void RipperDocGen::VisitAttribute( spAttribute& attr ) { wxString body; body += m_Tags[TAG_BOLD].start; body += attr.m_Type; body += m_Tags[TAG_BOLD].end; body += m_Tags[TAG_ITALIC].start; body += ' '; body += attr.GetName(); body += m_Tags[TAG_ITALIC].end; wxString line; AppendHighlightedSource( line, body ); AppendComments( attr, line ); ScriptSection* pSection = new ScriptSection( GetScopedName( attr ), line, &mSubContentTempl, GetRefTemplFor( attr ) ); if ( attr.mIsConstant ) mpConstIdx->AddSection( pSection, true ); else if ( !attr.IsInClass() ) { if ( CheckIfUncommented( attr, *mpGlobalVarsIdx ) ) return; mpGlobalVarsIdx->AddSection( pSection, true ); } else AddToCurrentClass( pSection, attr, "Attributes" ); } void RipperDocGen::VisitOperation( spOperation& op ) { wxString body; AppendHighlightedSource( body, op.GetFullName(m_Tags) ); AppendComments( op, body ); ScriptSection* pSection = new ScriptSection( GetScopedName( op ), body, &mSubContentTempl, GetRefTemplFor( op ) ); if ( !op.IsInClass() ) { if ( CheckIfUncommented( op, *mpGlobalFuncIdx ) ) return; mpGlobalFuncIdx->AddSection( pSection, 1 ); } else AddToCurrentClass( pSection, op, "Operations" ); } bool RipperDocGen::OnSaveDocument( ScriptStream& WXUNUSED(stm) ) { LinkSuperClassRefs(); // FOR NOW:: doesn't work yet //mpTopIdx->RemoveEmptySections(); return 1; // saving can proceed now }