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