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