1///////////////////////////////////////////////////////////////////////////// 2// Name: No names yet. 3// Purpose: Contrib. demo 4// Author: Aleksandras Gluchovas 5// Modified by: 6// Created: 22/09/98 7// RCS-ID: $Id: docripper.cpp 34519 2005-06-02 09:44:45Z ABX $ 8// Copyright: (c) Aleskandars Gluchovas 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12// For compilers that support precompilation, includes "wx/wx.h". 13#include "wx/wxprec.h" 14 15#ifdef __BORLANDC__ 16#pragma hdrstop 17#endif 18 19#ifndef WX_PRECOMP 20#include "wx/wx.h" 21#endif 22 23#include "docripper.h" 24 25#if wxUSE_IOSTREAMH 26 #include <iostream.h> 27#else 28 #include <iostream> 29#endif 30 31// script templates 32 33// ***** currently only HTML versions of variouse templates available ***** // 34 35static const char* HTM_TopTempl = 36 37"<html><body bgcolor=#FFFFFF>\n\ 38\n\n<!------ Automatically Generated by \"wxDocRipper\"------->\n\n\n\ 39<p><h2>$(NAME)</h2><p>\n\ 40<ul>\n\ 41$(REFLIST)\ 42</ul><p>\n\n\ 43"; 44 45static const char* HTM_ContentIdxTempl = 46 47"\ 48<a name=\"r$(ID)_$(NAME)\">\n\ 49<p><hr>\n\ 50<h2><p>$(NAME)<p></h2>\ 51<ul>\n\ 52$(REFLIST)\ 53</ul><p>\n\n\ 54"; 55 56static const char* HTM_SuperContentTempl = 57 58"\ 59<a name=\"r$(ID)_$(NAME)\">\n\ 60<p><hr>\n\ 61<p><h2>$(NAME)<p></h2>\ 62$(BODY)\n\ 63"; 64 65static const char* HTM_SubContentTempl = 66 67"\ 68<a name=\"r$(ID)_$(NAME)\">\n\ 69<p><hr>\n\ 70<p><h3>$(NAME)<p></h3>\ 71$(BODY)\n\ 72"; 73 74static const char* HTM_OutLineTempl = 75 76"\ 77<p>\n\ 78<b><font color=\"#FF0000\">$(NAME)</font></b><p>\n\ 79"; 80 81static const char* HTM_OutLine1Templ = 82 83"\ 84<p>\n\ 85<b><i><font color=\"#101010\">$(NAME)</font></i></b>\n\ 86<ul>\n\ 87$(REFLIST)\ 88</ul>\n\n\ 89"; 90 91static const char* HTM_RefTempl = 92 93"\ 94<li><a href=\"#r$(ID)_$(NAME)\">$(NAME)</A>\n\ 95"; 96 97static const char* HTM_DeadRefTempl = 98 99"\ 100<li></b>$(NAME)\n\ 101"; 102 103/***** Implementation for class RipperDocGen *****/ 104 105RipperDocGen::RipperDocGen() 106 107 : mTopTempl ( HTM_TopTempl ), 108 mContentIdxTempl ( HTM_ContentIdxTempl ), 109 mSuperContentTempl( HTM_SuperContentTempl ), 110 mSubContentTempl ( HTM_SubContentTempl ), 111 mOutLineTempl ( HTM_OutLineTempl ), 112 mOutLine1Templ ( HTM_OutLine1Templ ), 113 114 mRefTempl ( HTM_RefTempl ), 115 mDeadRefTempl ( HTM_DeadRefTempl ), 116 117 mpCurClassSect(0) 118{ 119 // topIndex is not referenced 120 mpTopIdx = new ScriptSection( "Source Code Contents" , wxEmptyString, &mTopTempl , 0 ); 121 mpClassIdx = new ScriptSection( "Classes Reference" , wxEmptyString, &mContentIdxTempl, &mRefTempl ); 122 mpEnumIdx = new ScriptSection( "Enumerations Reference" , wxEmptyString, &mContentIdxTempl, &mRefTempl ); 123 mpTypeDefIdx = new ScriptSection( "Type Definitions Reference" , wxEmptyString, &mContentIdxTempl, &mRefTempl ); 124 mpMacroIdx = new ScriptSection( "Macros Reference" , wxEmptyString, &mContentIdxTempl, &mRefTempl ); 125 mpGlobalVarsIdx = new ScriptSection( "Global Variables Reference" , wxEmptyString, &mContentIdxTempl, &mRefTempl ); 126 mpGlobalFuncIdx = new ScriptSection( "Global Functions Reference", wxEmptyString, &mContentIdxTempl, &mRefTempl ); 127 mpConstIdx = new ScriptSection( "Constants Reference" , wxEmptyString, &mContentIdxTempl, &mRefTempl ); 128 129 // assemble top index 130 mpTopIdx->AddSection( mpClassIdx , 1 ); 131 mpTopIdx->AddSection( mpEnumIdx , 1 ); 132 mpTopIdx->AddSection( mpTypeDefIdx , 1 ); 133 mpTopIdx->AddSection( mpMacroIdx , 1 ); 134 mpTopIdx->AddSection( mpGlobalVarsIdx, 1 ); 135 mpTopIdx->AddSection( mpGlobalFuncIdx, 1 ); 136 mpTopIdx->AddSection( mpConstIdx , 1 ); 137 138 // register reserved variables for index and description templates 139 ScriptSection::RegisterTemplate( mTopTempl ); 140 ScriptSection::RegisterTemplate( mContentIdxTempl ); 141 ScriptSection::RegisterTemplate( mSuperContentTempl ); 142 ScriptSection::RegisterTemplate( mSubContentTempl ); 143 ScriptSection::RegisterTemplate( mOutLineTempl ); 144 ScriptSection::RegisterTemplate( mOutLine1Templ ); 145 ScriptSection::RegisterTemplate( mRefTempl ); 146 ScriptSection::RegisterTemplate( mDeadRefTempl ); 147 148 // create the top-most (interfile) context 149 mpFileBinderCtx = new spFile(); 150 151 // the default script is HTML 152 m_Tags = get_HTML_markup_tags(); 153 154 mpParser = 0; // no default parser! 155} 156 157void RipperDocGen::Init( SourceParserBase* pParser ) 158{ 159 mpParser = pParser; 160} 161 162RipperDocGen::~RipperDocGen() 163{ 164 delete mpFileBinderCtx; 165} 166 167void RipperDocGen::AppendComments( spContext& fromContext, wxString& str ) 168{ 169 if ( !fromContext.HasComments() ) return; 170 171 size_t start = str.length(); 172 173 str += m_Tags[TAG_BOLD].end; 174 str += m_Tags[TAG_PARAGRAPH].start; 175 176 MCommentListT& lst = fromContext.GetCommentList(); 177 178 for( size_t i = 0; i != lst.size(); ++i ) 179 { 180 181 if ( i != 0 ) 182 183 if ( lst[i]->StartsParagraph() ) 184 { 185 str += m_Tags[TAG_PARAGRAPH].start; 186 } 187 188 str += lst[i]->m_Text; 189 } 190 191 // remove new lines, and insert paragraph breaks 192 193 // if empty lines found 194 195 size_t len = str.length(); 196 197 for( size_t n = start; n != len; ++n ) 198 199 if ( str[n] == 10 || 200 str[n] == 13 ) 201 { 202 if ( n + 2 < len ) 203 { 204 if ( ( str[n] == 13 && str[n+1] == 10 && // FIXME:: quick-hack 205 str[n+2] == 13 ) || 206 ( str[n] == 10 && str[n+1] == 10 ) 207 ) 208 { 209 str.insert( n + 1, _T("<p>") ); // FIXME:: quick-hack 210 len += 3; 211 } 212 } 213 str[n] = _T(' '); 214 } 215 str += m_Tags[TAG_PARAGRAPH].end; 216} 217 218void RipperDocGen::AppendMulitilineStr( wxString& st, wxString& mlStr ) 219{ 220 st = m_Tags[TAG_FIXED_FONT].start; 221 st += mlStr; 222 st += m_Tags[TAG_FIXED_FONT].end; 223} 224 225void RipperDocGen::AppendHighlightedSource( wxString& st, wxString source ) 226{ 227 // FIXME:: below should not be fixed :) 228 wxChar buf[1024*32]; 229 230 // DBG::: 231// ASSERT( source.length() + 1 < sizeof(buf) ); 232 233 wxStrcpy( buf, source.c_str() ); 234 235 // highlight things 236 mSrcPainter.Init(); 237 mSrcPainter.ProcessSource( buf, strlen(buf) ); 238 mSrcPainter.GetResultString( st, m_Tags ); 239} 240 241bool RipperDocGen::CheckIfUncommented( spContext& ctx, ScriptSection& toSect ) 242{ 243 if ( ctx.HasComments() ) return 0; 244 245 toSect.AddReference( 246 new ScriptSection( GetScopedName( ctx ), wxEmptyString, 0, &mDeadRefTempl ) 247 ); 248 249 return 1; 250} 251 252ScriptTemplate* RipperDocGen::GetRefTemplFor( spContext& ctx ) 253{ 254 if ( ctx.HasComments() ) 255 return &mRefTempl; 256 else 257 return &mDeadRefTempl; 258} 259 260wxString RipperDocGen::GetScopedName( spContext& ofCtx ) 261{ 262 if ( ofCtx.IsInFile() ) 263 return ofCtx.GetName(); 264 else 265 return ofCtx.GetOutterContext()->GetName() + 266 _T("::") + ofCtx.GetName(); 267} 268 269void RipperDocGen::AddToCurrentClass( ScriptSection* pSection, spContext& ctx, 270 const char* subSectionName ) 271{ 272 wxString sName; 273 274 if ( ctx.mVisibility == SP_VIS_PROTECTED ) 275 sName = "Protected members/"; 276 else 277 if ( ctx.mVisibility == SP_VIS_PRIVATE ) 278 sName = "Private members/"; 279 else 280 sName = "Public members/"; 281 282 sName += subSectionName; 283 284 ScriptSection* pSect = mpCurClassSect->GetSubsection( sName.c_str() ); 285 286 if ( CheckIfUncommented( ctx, *pSect ) ) 287 { 288 delete pSection; 289 return; 290 } 291 292 pSect->AddReference( pSection ); 293 294 mpCurClassSect->AddSection( pSection ); 295} 296 297void RipperDocGen::LinkSuperClassRefs() 298{ 299 MMemberListT clLst; 300 301 // collect all classes in the context tree 302 mpFileBinderCtx->GetContextList( clLst, SP_CTX_CLASS ); 303 304 for( size_t i = 0; i != clLst.size(); ++i ) 305 { 306 spClass& cl = *((spClass*)clLst[i]); 307 308 // FIXME:: why sometimes GetUserData() returns NULL? 309 if ( !cl.GetUserData() ) 310 continue; 311 312 ScriptSection* pClSect = (ScriptSection*)cl.GetUserData(); 313 ScriptSection* pSuperSect = pClSect->GetSubsection("Derived from"); 314 315 for( size_t n = 0; n != cl.m_SuperClassNames.size(); ++n ) 316 { 317 wxString& superClName = cl.m_SuperClassNames[n]; 318 319 spClass* pFound = NULL; 320 321 for( size_t k = 0; k != clLst.size(); ++k ) 322 { 323 if ( clLst[k]->GetName() == superClName ) 324 { 325 pFound = (spClass*)clLst[k]; 326 break; 327 } 328 } 329 330 if ( !pFound ) 331 { 332 ScriptSection* pNotFound = 333 new ScriptSection( superClName, wxEmptyString, 0, &mDeadRefTempl ); 334 335 pSuperSect->AddReference( pNotFound ); 336 } 337 else 338 if ( pFound->GetUserData() ) 339 340 pSuperSect->AddReference( 341 (ScriptSection*)pFound->GetUserData() ); 342 } 343 } 344} 345 346void RipperDocGen::ProcessFile( const char* sourceFile ) 347{ 348 wxSTD cout << "Processing file " << sourceFile << "..." << wxSTD endl; 349 350 spFile* pCtx = mpParser->ParseFile( sourceFile ); 351 352 if ( pCtx == NULL ) 353 { 354 wxSTD cout << "Cannot open file " << sourceFile << ", skipped..." << wxSTD endl; 355 356 return; 357 } 358 359 VisitAll( *pCtx, true ); 360 361 mpFileBinderCtx->AddMember( pCtx ); 362} 363 364// implementations of "visiting procedures" 365 366void RipperDocGen::VisitEnumeration( spEnumeration& en ) 367{ 368 // FOR NOW:: do not reference "nameless" enums 369 if ( en.GetName().empty() ) return; 370 371 if ( CheckIfUncommented( en, *mpEnumIdx ) ) 372 return; 373 374 wxString body; 375 body += m_Tags[TAG_BOLD].start; 376 377 AppendMulitilineStr( body, en.m_EnumContent ); 378 379 body += m_Tags[TAG_BOLD].end; 380 381 wxString line; 382 AppendHighlightedSource( line, body ); 383 AppendComments( en, line ); 384 385 mpEnumIdx->AddSection( 386 new ScriptSection( en.GetName(), line, 387 &mSubContentTempl, 388 GetRefTemplFor( en ) ), 1 389 ); 390} 391 392void RipperDocGen::VisitTypeDef( spTypeDef& td ) 393{ 394 if ( CheckIfUncommented( td, *mpTypeDefIdx ) ) 395 return; 396 397 wxString body; 398 body += m_Tags[TAG_BOLD].start; 399 body += "typdef "; 400 body += m_Tags[TAG_BOLD].end; 401 402 AppendMulitilineStr( body, td.m_OriginalType ); 403 body += td.m_OriginalType; 404 body += ' '; 405 406 body += m_Tags[TAG_BOLD].start; 407 body += td.GetName(); 408 body += m_Tags[TAG_BOLD].end; 409 410 wxString line; 411 AppendHighlightedSource( line, body ); 412 AppendComments( td, line ); 413 414 mpTypeDefIdx->AddSection( 415 new ScriptSection( td.GetName(), line, 416 &mSubContentTempl, 417 GetRefTemplFor( td ) ), true 418 ); 419} 420 421void RipperDocGen::VisitPreprocessorLine( spPreprocessorLine& pd ) 422{ 423 if ( pd.mDefType != SP_PREP_DEF_REDEFINE_SYMBOL ) 424 return; 425 426 if ( CheckIfUncommented( pd, *mpMacroIdx ) ) 427 return; 428 429 wxString body; 430 body += m_Tags[TAG_FIXED_FONT].start; 431 432 wxString coloredLine = pd.m_Line; 433 AppendHighlightedSource( coloredLine, pd.m_Line ); 434 435 AppendMulitilineStr( body, coloredLine ); 436 437 body += m_Tags[TAG_FIXED_FONT].end; 438 439 AppendComments( pd, body ); 440 441 mpMacroIdx->AddSection( 442 new ScriptSection( pd.GetName(), body, 443 &mSubContentTempl, 444 GetRefTemplFor( pd ) ), true 445 ); 446} 447 448void RipperDocGen::VisitClass( spClass& cl ) 449{ 450 // FOR NOW:: do not document nested classes - 451 // nicier visiting method yet needed 452 453 if ( cl.IsInClass() ) 454 { 455 SkipChildren(); // spVisitor's method 456 return; 457 } 458 459 wxString body; 460 AppendComments( cl, body ); 461 462 mpCurClassSect = 463 new ScriptSection( cl.GetName(), body, &mSuperContentTempl, &mRefTempl ); 464 465 // set up reference in the class context, pointing back 466 // to the section where this class is represented 467 cl.SetUserData( mpCurClassSect ); 468 469 ScriptSection* pSuper = new ScriptSection( "Derived from" ,wxEmptyString, &mOutLine1Templ,0, 1 ); 470 471 ScriptSection* pPublic = new ScriptSection( "Public members" ,wxEmptyString, &mOutLineTempl,0, 1 ); 472 ScriptSection* pProtected = new ScriptSection( "Protected members" ,wxEmptyString, &mOutLineTempl,0, 1 ); 473 ScriptSection* pPrivate = new ScriptSection( "Private members" ,wxEmptyString, &mOutLineTempl,0, 1 ); 474 475 pPublic->AddSection( new ScriptSection( "Operations", wxEmptyString, &mOutLine1Templ, 0, 1 ) ); 476 pPublic->AddSection( new ScriptSection( "Attributes", wxEmptyString, &mOutLine1Templ, 0, 1 ) ); 477 478 pProtected->AddSection( new ScriptSection( "Operations", wxEmptyString, &mOutLine1Templ, 0, 1 ) ); 479 pProtected->AddSection( new ScriptSection( "Attributes", wxEmptyString, &mOutLine1Templ, 0, 1 ) ); 480 481 pPrivate->AddSection( new ScriptSection( "Operations", wxEmptyString, &mOutLine1Templ, 0, 1 ) ); 482 pPrivate->AddSection( new ScriptSection( "Attributes", wxEmptyString, &mOutLine1Templ, 0, 1 ) ); 483 484 mpCurClassSect->AddSection( pSuper ); 485 mpCurClassSect->AddSection( pPublic ); 486 mpCurClassSect->AddSection( pProtected ); 487 mpCurClassSect->AddSection( pPrivate ); 488 489 mpClassIdx->AddSection( mpCurClassSect, true ); 490} 491 492void RipperDocGen::VisitAttribute( spAttribute& attr ) 493{ 494 wxString body; 495 body += m_Tags[TAG_BOLD].start; 496 body += attr.m_Type; 497 body += m_Tags[TAG_BOLD].end; 498 499 body += m_Tags[TAG_ITALIC].start; 500 body += ' '; 501 body += attr.GetName(); 502 body += m_Tags[TAG_ITALIC].end; 503 504 wxString line; 505 AppendHighlightedSource( line, body ); 506 AppendComments( attr, line ); 507 508 ScriptSection* pSection = 509 new ScriptSection( GetScopedName( attr ), line, 510 &mSubContentTempl, 511 GetRefTemplFor( attr ) ); 512 513 if ( attr.mIsConstant ) 514 mpConstIdx->AddSection( pSection, true ); 515 else 516 if ( !attr.IsInClass() ) 517 { 518 if ( CheckIfUncommented( attr, *mpGlobalVarsIdx ) ) 519 return; 520 mpGlobalVarsIdx->AddSection( pSection, true ); 521 } 522 else 523 AddToCurrentClass( pSection, attr, "Attributes" ); 524} 525 526void RipperDocGen::VisitOperation( spOperation& op ) 527{ 528 wxString body; 529 530 AppendHighlightedSource( body, op.GetFullName(m_Tags) ); 531 532 AppendComments( op, body ); 533 534 ScriptSection* pSection = 535 new ScriptSection( GetScopedName( op ), body, 536 &mSubContentTempl, 537 GetRefTemplFor( op ) ); 538 539 if ( !op.IsInClass() ) 540 { 541 if ( CheckIfUncommented( op, *mpGlobalFuncIdx ) ) 542 return; 543 544 mpGlobalFuncIdx->AddSection( pSection, 1 ); 545 } 546 else 547 AddToCurrentClass( pSection, op, "Operations" ); 548} 549 550bool RipperDocGen::OnSaveDocument( ScriptStream& WXUNUSED(stm) ) 551{ 552 LinkSuperClassRefs(); 553 554 // FOR NOW:: doesn't work yet 555 //mpTopIdx->RemoveEmptySections(); 556 557 return 1; // saving can proceed now 558} 559 560