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