]> git.saurik.com Git - wxWidgets.git/blob - utils/HelpGen/src/scriptbinder.cpp
fatal bug in wxMGL that caused hard to track crashes
[wxWidgets.git] / utils / HelpGen / src / scriptbinder.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 <malloc.h>
24 #include <string.h>
25 #include <memory.h>
26
27 #include <stdio.h> // import sprintf() (for doubles)
28 #include <stdlib.h> // import atoi() (for integers)
29
30 #include "scriptbinder.h"
31
32 // helper functions
33
34 static size_t log2(size_t nr)
35 {
36 size_t tmp = 0;
37 while (nr >= 2 )
38 {
39 nr /= 2;
40 ++tmp;
41 }
42
43 return tmp;
44 }
45
46 /***** Implementation for class ScriptStream *****/
47
48 ScriptStream::ScriptStream()
49 : mpBuf(0),
50 mSize(0),
51 mCapacity(0)
52 {}
53
54 ScriptStream::~ScriptStream()
55 {
56 if ( mpBuf ) delete mpBuf;
57 }
58
59 void ScriptStream::WriteBytes( const void* srcBuf, size_t count )
60 {
61 if ( !count ) return;
62
63 // increase the capacity if necessary
64 if ( mSize + count > mCapacity )
65 {
66 mCapacity =
67 ( 0x2 << (log2( mSize + count ) + 1 ) );
68
69 if ( mCapacity < 128 ) mCapacity = 128;
70
71 char* oldBuf = mpBuf;
72
73 mpBuf = new char[mCapacity];
74
75 if ( oldBuf )
76 {
77 memcpy( mpBuf, oldBuf, mSize );
78 delete oldBuf;
79 }
80 }
81
82 // append new data
83 memcpy( &mpBuf[mSize], srcBuf, count );
84
85 mSize += count;
86 }
87
88 ScriptStream& ScriptStream::operator<<( const char* str )
89 {
90 WriteBytes( str, strlen( str ) );
91
92 return *this;
93 }
94
95 ScriptStream& ScriptStream::operator<<( const string& str )
96 {
97 if ( str.length() < 512 )
98 {
99 char buf[512];
100 size_t len = str.length();
101
102 for( size_t i = 0; i != len; ++i )
103 buf[i] = str[i];
104
105 WriteBytes( buf, len );
106 }
107 else
108 WriteBytes( str.c_str(), str.length() );
109
110 return *this;
111 }
112
113 ScriptStream& ScriptStream::operator<<( char ch )
114 {
115 WriteBytes( &ch, 1 );
116
117 return *this;
118 }
119
120 void ScriptStream::endl()
121 {
122 char ch = '\n';
123 WriteBytes( &ch, 1 );
124 }
125
126 /***** Implementation for class ScriptTemplate *****/
127
128 ScriptTemplate::ScriptTemplate( const string& templateText )
129 {
130 string tmp = templateText;
131
132 mTText = (char*)malloc( tmp.length() + 1 );
133
134 strcpy( mTText, tmp.c_str() );
135 }
136
137 ScriptTemplate::~ScriptTemplate()
138 {
139 for( size_t i = 0; i != mVars.size(); ++i )
140
141 delete mVars[i];
142
143 free( mTText );
144 }
145
146 bool ScriptTemplate::HasVar( const char* name )
147 {
148 for( size_t i = 0; i != mVars.size(); ++i )
149
150 if ( strcmp( mVars[i]->mName, name ) == 0 )
151
152 return 1;
153
154 return 0;
155 }
156
157 void ScriptTemplate::AddStringVar ( const char* name, int ofs )
158 {
159 mVars.push_back( new TVarInfo( name, ofs, TVAR_STRING ) );
160 }
161
162 void ScriptTemplate::AddIntegerVar( const char* name, int ofs )
163 {
164 mVars.push_back( new TVarInfo( name, ofs, TVAR_INTEGER ) );
165 }
166
167 void ScriptTemplate::AddDoubleVar ( const char* name, int ofs )
168 {
169 mVars.push_back( new TVarInfo( name, ofs, TVAR_DOUBLE ) );
170 }
171
172 void ScriptTemplate::AddObjectRefArray( const char* name,
173 int ofsRefToFirstObj,
174 int ofsObjSizeInt,
175 int ofsObjRefTempl
176 )
177 {
178 TArrayInfo* pInfo = new TArrayInfo( name );
179
180 mVars.push_back( pInfo );
181
182 pInfo->mRefOfs = ofsRefToFirstObj;
183 pInfo->mSizeIntOfs = ofsObjSizeInt;
184 pInfo->mObjRefTemplOfs = ofsObjRefTempl;
185 }
186
187 inline void ScriptTemplate::PrintVar( TVarInfo* pInfo,
188 void* dataObj,
189 ScriptStream& stm )
190 {
191 char buf[128];
192
193 switch ( pInfo->mType )
194 {
195 case TVAR_INTEGER :
196 {
197 sprintf(buf, "%d",*( (int*) ((char*)dataObj + pInfo->mOfs) ) );
198
199 stm.WriteBytes( buf, strlen(buf ) );
200 break;
201 }
202
203 case TVAR_STRING :
204 {
205 string& str = *( (string*) ((char*)dataObj+pInfo->mOfs) );
206
207 const char* cs = str.c_str();
208 #ifdef DEBUG_WEIRED_OFFSETS
209 cout << "DBG:: cs address is " << (int)cs << endl;
210 cout << "DBG:: str address is " << (int)(&str) << endl;
211 cout << "DBG:: dataObj points to " << (int)dataObj << endl;
212 cout << "DBG:: pInfo->mOfs value is " << (int)pInfo->mOfs << endl;
213 cout << "DBG:: d+pInfo->mOfs is " << (int)((char*)dataObj + pInfo->mOfs) << endl;
214 cout << "DBG:: pInfo->mName is " << pInfo->mName << endl;
215 cout << "DBG:: pInfo->mType is " << pInfo->mType << endl;
216 cout << "DBG:: end of dump. " << endl;
217
218 cout << "DBG:: cs value is " << endl << cs << endl;
219 #endif
220 stm.WriteBytes( cs, strlen(cs) );
221 break;
222 }
223
224 case TVAR_DOUBLE :
225 {
226 sprintf( buf, "%f",
227 *( (double*)( (char*)dataObj+pInfo->mOfs) ) );
228
229 stm.WriteBytes( buf, strlen(buf ) );
230 break;
231 }
232
233 case TVAR_REF_ARRAY :
234 {
235 TArrayInfo& info = *((TArrayInfo*)pInfo);
236
237 int sz = *((int*) ( (char*)dataObj+info.mSizeIntOfs ));
238 if ( !sz )
239 {
240 // DBG::
241 int u = 0;
242 ++u;
243 break;
244 }
245
246 int* array = *((int**)( (char*)dataObj+info.mRefOfs ));
247
248 ScriptTemplate* pRefTempl;
249
250 for( int i = 0; i != sz; ++i )
251 {
252 pRefTempl =
253 *((ScriptTemplate**)((char*)(array[i])+info.mObjRefTemplOfs));
254
255 pRefTempl->PrintScript( (void*)array[i], stm );
256 }
257
258 break;
259 }
260
261 default : break;
262 }
263 }
264
265 void ScriptTemplate::PrintScript( void* dataObj, ScriptStream& stm )
266 {
267 char* cur = mTText;
268
269 // template parsing loop
270 do
271 {
272 char* start = cur;
273
274 while( *cur != '\0' && *cur != '$' ) ++cur;
275
276 // flush text collected between variables
277 stm.WriteBytes( start, cur - start );
278
279 if ( *cur == '\0' ) break;
280
281 cur += 2; // skip to the name of the var
282
283 start = cur;
284
285 while( *cur != ')' ) ++cur;
286
287 // put terminating zero temorarely
288
289 *cur = '\0';
290
291 // look up variable
292
293 size_t sz = mVars.size();
294 bool found = 0;
295
296 for( size_t i = 0; i != sz; ++i )
297 {
298 if ( strcmp( mVars[i]->mName, start ) == 0 )
299 {
300 PrintVar( mVars[i], dataObj, stm );
301
302 *cur = ')'; // remove terminating zero
303 ++cur;
304 found = 1;
305 break;
306 }
307 }
308
309 // variable referred by template script is not
310 // registered to this tempalte object
311 // ASSERT( found );
312
313 } while(1);
314 }
315
316 /***** implementation for class ScriptSection *****/
317
318 int ScriptSection::mIdCounter = 0;
319
320 ScriptSection::ScriptSection( const string& name,
321 const string& body,
322 ScriptTemplate* pSectionTemplate,
323 ScriptTemplate* pReferenceTemplate,
324 bool autoHide,
325 bool sorted
326 )
327 : mpParent ( NULL ),
328
329 mName ( name ),
330 mBody ( body ),
331
332 mAutoHide( autoHide ),
333 mSortOn ( sorted ),
334
335 mpSectTempl( pSectionTemplate ),
336 mpRefTempl ( pReferenceTemplate ),
337
338 mRefCount( 0 ),
339 mArrSize( 0 )
340 {
341 // generate GUID
342
343 char buf[32];
344 sprintf( buf, "%d", ++mIdCounter );
345 mId = buf;
346 }
347
348 ScriptSection::~ScriptSection()
349 {
350 SectListT lst = mSubsections;
351
352 while( mSubsections.size() )
353
354 mSubsections[0]->RemoveRef();
355
356 for( size_t i = 0; i != mReferences.size(); ++i )
357
358 mReferences[i]->RemoveRef();
359 }
360
361 void ScriptSection::AddRef()
362 {
363 ++mRefCount;
364 }
365
366 void ScriptSection::RemoveRef()
367 {
368 if ( !mRefCount || !(--mRefCount) )
369 {
370 if (mpParent)
371 {
372 // remove ourselves from parent's list
373
374 SectListT& lst = mpParent->mSubsections;
375 for( size_t i = 0; i != lst.size(); ++i )
376
377 if ( lst[i] == this )
378 {
379 lst.erase( &lst[i] );
380 break;
381 }
382 }
383
384 delete this;
385 }
386 }
387
388 ScriptSection* ScriptSection::GetSubsection( const char* name )
389 {
390 // FOR NOW:: fixed section name length
391 char buf[128];
392
393 size_t cur = 0;
394
395 while( name[cur] && name[cur] != '/' )
396 {
397 buf[cur] = name[cur];
398 ++cur;
399 }
400
401 // ASSERT( cur < sizeof(buf) );
402
403 buf[cur] = '\0';
404
405 size_t sz = mSubsections.size();
406
407 for( size_t i = 0; i != sz; ++i )
408 {
409 // DBG::
410 //ScriptSection& sect = *mSubsections[i];
411
412 if ( mSubsections[i]->mName == buf )
413 {
414 if ( name[cur] == '/' )
415
416 // search recursivelly
417 return mSubsections[i]->GetSubsection( &name[cur+1] );
418 else
419 return mSubsections[i];
420 }
421 }
422
423 return 0;
424 }
425
426 void ScriptSection::AddSection( ScriptSection* pSection,
427 bool addToReferencesToo
428 )
429 {
430 mSubsections.push_back( pSection );
431
432 pSection->AddRef();
433
434 // can add section to multiple containers
435 // ASSERT( pSection->mpParent == 0 );
436
437 pSection->mpParent = this;
438
439 if ( addToReferencesToo )
440
441 AddReference( pSection );
442 }
443
444 void ScriptSection::AddReference( ScriptSection* pReferredSection )
445 {
446 mReferences.push_back( pReferredSection );
447
448 pReferredSection->AddRef();
449
450 // set up mandatory fields used by ScriptTemplate
451 mArrSize = mReferences.size();
452 if ( mArrSize )
453 mRefFirst = (void*)&mReferences[0];
454 }
455
456 SectListT& ScriptSection::GetSubsections()
457 {
458 return mSubsections;
459 }
460
461 // static method:
462 void ScriptSection::RegisterTemplate( ScriptTemplate& sectionTempalte )
463 {
464 int nameOfs, bodyOfs, idOfs,
465 arrRefOfs, arrSizeOfs, refTemplOfs;
466
467 // obtaining offsets of member vars
468
469 GET_VAR_OFS( ScriptSection, mName, &nameOfs )
470 GET_VAR_OFS( ScriptSection, mBody, &bodyOfs )
471 GET_VAR_OFS( ScriptSection, mId, &idOfs )
472 GET_VAR_OFS( ScriptSection, mRefFirst, &arrRefOfs )
473 GET_VAR_OFS( ScriptSection, mArrSize, &arrSizeOfs )
474
475 GET_VAR_OFS( ScriptSection, mpRefTempl, &refTemplOfs )
476
477 // registering member variables with given script template
478
479 sectionTempalte.AddStringVar( "NAME", nameOfs );
480 sectionTempalte.AddStringVar( "BODY", bodyOfs );
481 sectionTempalte.AddStringVar( "ID", idOfs );
482
483 sectionTempalte.AddObjectRefArray( "REFLIST",
484 arrRefOfs, arrSizeOfs, refTemplOfs );
485 }
486
487 void ScriptSection::Print( ScriptStream& stm )
488 {
489 // TBD:: sorting
490
491 // print out this content first
492 if ( mpSectTempl )
493
494 mpSectTempl->PrintScript( this, stm );
495
496 // attach contents subsections at the end of this content
497
498 for( size_t i = 0; i != mSubsections.size(); ++i )
499
500 mSubsections[i]->Print( stm );
501 }
502
503 void ScriptSection::DoRemoveEmptySections(int& nRemoved, SectListT& removedLst)
504 {
505 for( size_t i = 0; i != mSubsections.size(); ++i )
506 {
507 ScriptSection& sect = *mSubsections[i];
508
509 sect.DoRemoveEmptySections( nRemoved, removedLst );
510
511 if (sect.mAutoHide )
512
513 if ( sect.mReferences.size() == 0 )
514 {
515 bool found = 0;
516 for( size_t k = 0; k != removedLst.size(); ++k )
517
518 if ( removedLst[k] == &sect )
519 {
520 found = 1;
521 break;
522 }
523
524 if ( !found )
525 {
526 removedLst.push_back( &sect );
527 ++nRemoved;
528
529 delete &sect;
530 --i;
531 }
532 }
533 }
534 }
535
536 void ScriptSection::DoRemoveDeadLinks( SectListT& removedLst)
537 {
538 size_t dsz = removedLst.size();
539
540 for( size_t i = 0; i != mSubsections.size(); ++i )
541 {
542 mSubsections[i]->DoRemoveDeadLinks( removedLst );
543 }
544
545 for( size_t n = 0; n != mReferences.size(); ++n )
546 {
547 for( size_t k = 0; k != dsz; ++k )
548
549 if ( removedLst[k] == mReferences[n] )
550 {
551 mReferences.erase( &mReferences[n] );
552 --n;
553
554 // set up mandatory fields used by ScriptTemplate
555 mArrSize = mReferences.size();
556 if ( mArrSize )
557 mRefFirst = (void*)&mReferences[0];
558
559 break;
560 }
561 }
562 }
563
564
565 void ScriptSection::RemoveEmptySections()
566 {
567 // FIXME:: this is very_very_very slow alg.! +"doesn't work"
568
569 int nRemoved = 0;
570
571 do
572 {
573 SectListT removedLst;
574 nRemoved = 0;
575
576 DoRemoveEmptySections( nRemoved, removedLst );
577
578 DoRemoveDeadLinks( removedLst );
579 }
580 while( nRemoved );
581 }
582
583 /***** Iimplementation for class DocGeneratorBase *****/
584
585 bool DocGeneratorBase::SaveDocument( const char* fname,
586 const char* fopenOptions,
587 ScriptSection* pFromSection
588 )
589 {
590 FILE* fp = fopen( fname, fopenOptions );
591
592 if ( (int)fp == -1 ) return 0;
593
594 ScriptStream stm;
595
596 // check if derived class agrees about saving it
597 if ( !OnSaveDocument( stm ) ) return 0;
598
599 if ( pFromSection )
600
601 pFromSection->Print( stm );
602 else
603 {
604 ScriptSection* pTopSect = GetTopSection();
605 // ASSERT( pTopSect );
606 pTopSect->Print( stm );
607 }
608
609 size_t nWrite = fwrite( stm.GetBuf(), 1, stm.GetBufSize(), fp );
610
611 if ( nWrite != stm.GetBufSize() ) return 0;
612
613 fclose( fp );
614
615 return 1;
616
617 // that^s it
618 }