]> git.saurik.com Git - wxWidgets.git/blobdiff - utils/HelpGen/src/docripper.cpp
HelpGen is a prototype of the tool for automatic generation of the .tex files
[wxWidgets.git] / utils / HelpGen / src / docripper.cpp
diff --git a/utils/HelpGen/src/docripper.cpp b/utils/HelpGen/src/docripper.cpp
new file mode 100644 (file)
index 0000000..cdaff81
--- /dev/null
@@ -0,0 +1,568 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        No names yet.
+// Purpose:     Contrib. demo
+// Author:      Aleksandras Gluchovas
+// Modified by:
+// Created:     22/09/98
+// RCS-ID:      $Id$
+// 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"
+
+#include <iostream.h>
+
+// script templates
+
+// ***** currently only HTML versions of variouse templates available ***** //
+
+static const char* HTM_TopTempl = 
+
+"<html><body bgcolor=#FFFFFF>\n\
+\n\n<!------ Automatically Generated by \"wxDocRipper\"------->\n\n\n\
+<p><h2>$(NAME)</h2><p>\n\
+<ul>\n\
+$(REFLIST)\
+</ul><p>\n\n\
+";
+
+static const char* HTM_ContentIdxTempl = 
+
+"\
+<a name=\"r$(ID)_$(NAME)\">\n\
+<p><hr>\n\
+<h2><p>$(NAME)<p></h2>\
+<ul>\n\
+$(REFLIST)\
+</ul><p>\n\n\
+";
+
+static const char* HTM_SuperContentTempl = 
+
+"\
+<a name=\"r$(ID)_$(NAME)\">\n\
+<p><hr>\n\
+<p><h2>$(NAME)<p></h2>\
+$(BODY)\n\
+";
+
+static const char* HTM_SubContentTempl = 
+
+"\
+<a name=\"r$(ID)_$(NAME)\">\n\
+<p><hr>\n\
+<p><h3>$(NAME)<p></h3>\
+$(BODY)\n\
+";
+
+static const char* HTM_OutLineTempl =
+
+"\
+<p>\n\
+<b><font color=\"#FF0000\">$(NAME)</font></b><p>\n\
+";
+
+static const char* HTM_OutLine1Templ =
+
+"\
+<p>\n\
+<b><i><font color=\"#101010\">$(NAME)</font></i></b>\n\
+<ul>\n\
+$(REFLIST)\
+</ul>\n\n\
+";
+
+static const char* HTM_RefTempl =
+
+"\
+<li><a href=\"#r$(ID)_$(NAME)\">$(NAME)</A>\n\
+";
+
+static const char* HTM_DeadRefTempl =
+
+"\
+<li></b>$(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"       , "", &mTopTempl       , 0          );
+       mpClassIdx      = new ScriptSection( "Classes Reference"          , "", &mContentIdxTempl, &mRefTempl );
+       mpEnumIdx       = new ScriptSection( "Enumerations  Reference"    , "", &mContentIdxTempl,  &mRefTempl );
+       mpTypeDefIdx    = new ScriptSection( "Type Definitions Reference" , "", &mContentIdxTempl, &mRefTempl );
+       mpMacroIdx      = new ScriptSection( "Macros Reference"           , "", &mContentIdxTempl, &mRefTempl );
+       mpGlobalVarsIdx = new ScriptSection( "Global Variables Reference" , "", &mContentIdxTempl, &mRefTempl );
+       mpGlobalFuncIdx = new ScriptSection( "Global Functions  Reference", "", &mContentIdxTempl, &mRefTempl );
+       mpConstIdx      = new ScriptSection( "Constants  Reference"       , "", &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
+       mTags = 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, string& str )
+{
+       if ( !fromContext.HasComments() ) return;
+
+       size_t start = str.length();
+
+       str += mTags[TAG_BOLD].end;
+       str += mTags[TAG_PARAGRAPH].start;
+
+       MCommentListT& lst = fromContext.GetCommentList();
+
+       for( size_t i = 0; i != lst.size(); ++i )
+       {
+       
+               if ( i != 0 )
+                       
+                       if ( lst[i]->StartsParagraph() )
+                       {
+                               str += mTags[TAG_PARAGRAPH].start;
+                       }
+       
+               str += lst[i]->mText;
+       }
+
+       // 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, "<p>" ); // FIXME:: quick-hack
+                                       len += 3;
+                               }
+                       }
+
+                       str[n] = ' ';
+               }
+
+       str += mTags[TAG_PARAGRAPH].end;
+}
+
+void RipperDocGen::AppendMulitilineStr( string& st, string& mlStr )
+{
+       st = mTags[TAG_FIXED_FONT].start;
+       st += mlStr;
+       st += mTags[TAG_FIXED_FONT].end;
+}
+
+void RipperDocGen::AppendHighlightedSource( string& st, string source )
+{
+       // FIXME:: below should not be fixed :)
+       char buf[1024*32];
+
+       // DBG:::
+       ASSERT( source.length() + 1 < sizeof(buf) );
+
+       strcpy( buf, source.c_str() );
+                                               
+       // highlight things
+       mSrcPainter.Init();
+       mSrcPainter.ProcessSource( buf, strlen(buf) );
+       mSrcPainter.GetResultString( st, mTags );
+}
+
+bool RipperDocGen::CheckIfUncommented( spContext& ctx, ScriptSection& toSect )
+{
+       if ( ctx.HasComments() ) return 0;
+
+       toSect.AddReference( 
+               new ScriptSection( GetScopedName( ctx ), "", 0, &mDeadRefTempl )
+       );
+
+       return 1;
+}
+
+ScriptTemplate* RipperDocGen::GetRefTemplFor( spContext& ctx )
+{
+       if ( ctx.HasComments() )
+
+               return &mRefTempl;
+       else
+               return &mDeadRefTempl;
+}
+
+string RipperDocGen::GetScopedName( spContext& ofCtx )
+{
+       if ( ofCtx.IsInFile() ) return ofCtx.GetName();
+       else
+               return ofCtx.GetOutterContext()->GetName() + 
+                          "::" + ofCtx.GetName();
+}
+
+void RipperDocGen::AddToCurrentClass( ScriptSection* pSection, spContext& ctx, 
+                                                                         const char* subSectionName )
+{
+       string 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.mSuperClassNames.size(); ++n )
+               {
+                       string& superClName = cl.mSuperClassNames[n];
+
+                       spClass* pFound = NULL;
+
+                       string* name;
+
+                       for( size_t k = 0; k != clLst.size(); ++k )
+                       {
+                               name = &clLst[k]->GetName();
+
+                               if ( clLst[k]->GetName() == superClName )
+                               {
+                                       pFound = (spClass*)clLst[k];
+                                       break;
+                               }
+                       }
+
+                       if ( !pFound )
+                       {
+                               ScriptSection* pNotFound = 
+                                       new ScriptSection( superClName, "", 0, &mDeadRefTempl );
+
+                               pSuperSect->AddReference( pNotFound );
+                       }
+                       else
+                               if ( pFound->GetUserData() )
+                               
+                                       pSuperSect->AddReference( 
+                                               (ScriptSection*)pFound->GetUserData() );
+               }
+       }
+}
+
+void RipperDocGen::ProcessFile( const char* sourceFile )
+{
+       cout << "Processing file " << sourceFile << "..." << endl;
+
+       spFile* pCtx = mpParser->ParseFile( sourceFile );
+
+       if ( pCtx == NULL )
+       {
+               cout << "Cannot open file " << sourceFile << ", skipped..." << 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() == "" ) return;
+
+       if ( CheckIfUncommented( en, *mpEnumIdx ) )
+               return;
+
+       string body;
+       body += mTags[TAG_BOLD].start;
+
+       AppendMulitilineStr( body, en.mEnumContent );
+
+       body += mTags[TAG_BOLD].end;
+
+       string 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;
+
+       string body;
+       body += mTags[TAG_BOLD].start;
+       body += "typdef ";
+       body += mTags[TAG_BOLD].end;
+
+       AppendMulitilineStr( body, td.mOriginalType );
+       body += td.mOriginalType;
+       body += ' ';
+
+       body += mTags[TAG_BOLD].start;
+       body += td.GetName();
+       body += mTags[TAG_BOLD].end;
+
+       string 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;
+
+       string body;
+       body += mTags[TAG_FIXED_FONT].start;
+
+       string coloredLine = pd.mLine;
+       AppendHighlightedSource( coloredLine, pd.mLine );
+
+       AppendMulitilineStr( body, coloredLine );
+
+       body += mTags[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;
+       }
+
+       string 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"    ,"", &mOutLine1Templ,0, 1 );
+
+       ScriptSection* pPublic    = new ScriptSection( "Public members"    ,"", &mOutLineTempl,0, 1 );
+       ScriptSection* pProtected = new ScriptSection( "Protected members" ,"", &mOutLineTempl,0, 1 );
+       ScriptSection* pPrivate   = new ScriptSection( "Private members"   ,"", &mOutLineTempl,0, 1 );
+
+       pPublic->AddSection( new ScriptSection( "Operations", "", &mOutLine1Templ, 0, 1 ) );
+       pPublic->AddSection( new ScriptSection( "Attributes", "", &mOutLine1Templ, 0, 1 ) );
+
+
+       pProtected->AddSection( new ScriptSection( "Operations", "", &mOutLine1Templ, 0, 1 ) );
+       pProtected->AddSection( new ScriptSection( "Attributes", "", &mOutLine1Templ, 0, 1 ) );
+
+
+       pPrivate->AddSection( new ScriptSection( "Operations", "", &mOutLine1Templ, 0, 1 ) );
+       pPrivate->AddSection( new ScriptSection( "Attributes", "", &mOutLine1Templ, 0, 1 ) );
+
+       mpCurClassSect->AddSection( pSuper    );
+       mpCurClassSect->AddSection( pPublic    );
+       mpCurClassSect->AddSection( pProtected );
+       mpCurClassSect->AddSection( pPrivate   );
+
+       mpClassIdx->AddSection( mpCurClassSect, TRUE );
+}
+
+void RipperDocGen::VisitAttribute( spAttribute& attr )
+{
+       string body;
+       body += mTags[TAG_BOLD].start;
+       body += attr.mType;
+       body += mTags[TAG_BOLD].end;
+
+       body += mTags[TAG_ITALIC].start;
+       body += ' ';
+       body += attr.GetName();
+       body += mTags[TAG_ITALIC].end;
+
+       string 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 )
+{
+       string body;
+
+       AppendHighlightedSource( body, op.GetFullName(mTags) );
+
+       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& stm )
+{
+       LinkSuperClassRefs();
+
+       // FOR NOW:: doesn't work yet
+       //mpTopIdx->RemoveEmptySections();
+
+       return 1; // saving can proceed now 
+}
+