1/////////////////////////////////////////////////////////////////////////////
2// Name:        No names yet.
3// Purpose:     Contrib. demo
4// Author:      Aleksandras Gluchovas
5// Modified by:
6// Created:     27/12/98
7// RCS-ID:      $Id: ifcontext.cpp 40162 2006-07-17 13:17:57Z MW $
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 <stdio.h>
24
25#include "ifcontext.h"
26
27/***** Implementation for class spInterFileContext *****/
28
29size_t spInterFileContext::GetFileNo( const wxString& fname )
30{
31    for ( size_t i = 0; i != m_Files.size(); ++i )
32    {
33        if ( fname == m_Files[i] )
34            return i;
35    }
36
37    wxFAIL_MSG("File not found in array in function spInterFileContext::GetFileNo()");
38
39    return 0;
40}
41
42size_t spInterFileContext::GetFileNoOfContext( spContext& ctx )
43{
44    spContext* pCtx = ctx.GetEnclosingContext( SP_CTX_FILE );
45
46    // DBG:: outer-file context should be present
47    wxASSERT( pCtx && pCtx->GetType() == SP_CTX_FILE );
48
49    return GetFileNo( ((spFile*)pCtx)->m_FileName );
50}
51
52/*** public interface ***/
53
54spInterFileContext::spInterFileContext()
55{}
56
57spInterFileContext::~spInterFileContext()
58{}
59
60void spInterFileContext::AddFile( const wxString& fname, const wxString& content )
61{
62    m_Files.push_back( fname );
63    m_Contents.push_back( content );
64}
65
66void spInterFileContext::RemoveContext( spContext& ctx )
67{
68    wxASSERT( ctx.PositionIsKnown() ); // DBG:: should be checked by-user code
69
70    size_t fNo = GetFileNoOfContext( ctx );
71
72    mDeletionMarks.push_back( spBookmark( ctx.mSrcOffset, ctx.mContextLength, fNo ) );
73}
74
75void spInterFileContext::InsertBookmarkSorted( BookmarkListT& lst, spBookmark& mark )
76{
77    for( size_t i = 0; i != lst.size(); ++i )
78
79    if ( lst[i].mFrom > mark.mFrom )
80    {
81        lst.insert( &lst[i], mark );
82        return;
83    }
84
85    lst.push_back( mark );
86}
87
88void spInterFileContext::DoAppendSourceFragment( wxString& source,
89                                                 wxString& result,
90                                                 size_t  pos, size_t len )
91{
92    mFiltered.erase( mFiltered.begin(), mFiltered.end() );
93
94    size_t i;
95
96    for( i = 0; i != mDeletionMarks.size(); ++i )
97    {
98        spBookmark& mark = mDeletionMarks[i];
99
100        if ( mark.mFileNo == mCurFileNo &&
101             mark.mFrom >= pos && mark.mFrom < pos + len )
102
103        InsertBookmarkSorted( mFiltered, mark );
104    }
105
106    size_t cur = pos;
107
108    for( i = 0; i != mFiltered.size(); ++ i )
109    {
110        spBookmark& mark = mFiltered[i];
111
112        result.append( source, cur, ( (size_t)mark.mFrom - cur ) );
113
114        cur = size_t( mark.mFrom + mark.mLen );
115
116        if ( cur >= pos + len ) // check if we've overstepped the current source-fragment
117        {
118//            wxASSERT(0); // DBG:: with current imp. this should not happen
119            wxFAIL_MSG("Overstepped the current source fragment in function\nspInterFileContext::DoAppendSourceFragment()");
120            cur = pos + len; break;
121        }
122    }
123
124    result.append( source, cur, ( pos + len ) - cur );
125}
126
127void spInterFileContext::GenerateContextBody( spContext& ctx,
128                                              wxString&  source,
129                                              wxString&  result,
130                                              size_t&    lastSavedPos,
131                                              size_t&    lastKnownPos )
132{
133    if ( ctx.PositionIsKnown() )
134        lastKnownPos = ctx.mSrcOffset;
135
136    if ( ctx.IsVirtualContext() )
137    {
138        // add fragment accumulated before this context
139
140        DoAppendSourceFragment( source, result,
141                                size_t(lastSavedPos),
142                                size_t(lastKnownPos - lastSavedPos) );
143
144        // add context body
145
146        result += ctx.GetVirtualContextBody();
147
148        lastSavedPos = lastKnownPos;
149
150        if ( ctx.PositionIsKnown() )
151        {
152            if ( ctx.VitualContextHasChildren() )
153            {
154                lastKnownPos = ctx.mSrcOffset + ctx.mHeaderLength;
155
156                lastSavedPos = lastKnownPos;
157            }
158            else
159            {
160                lastKnownPos = ctx.mSrcOffset + ctx.mContextLength;
161
162                lastSavedPos = lastKnownPos;
163
164                return; // have not children
165            }
166        }
167    }
168
169    MMemberListT& lst = ctx.GetMembers();
170
171    for( size_t i = 0; i != lst.size(); ++i )
172    {
173        GenerateContextBody( *lst[i], source, result, lastSavedPos, lastKnownPos );
174    }
175
176    if ( ctx.IsVirtualContext() )
177    {
178        if ( ctx.VitualContextHasChildren() && !ctx.GetFooterOfVirtualContextBody().empty() )
179        {
180            // append the reminder space after children of the context
181
182            DoAppendSourceFragment( result, source,
183                                    size_t(lastSavedPos),
184                                    size_t(lastKnownPos - lastSavedPos) );
185
186            // add footer
187            result += ctx.GetFooterOfVirtualContextBody();
188
189            lastKnownPos = ctx.mSrcOffset + ctx.mContextLength;
190
191            lastSavedPos = lastKnownPos;
192        }
193    }
194
195    if ( ctx.PositionIsKnown() )
196
197        lastKnownPos = ctx.mSrcOffset + ctx.mContextLength;
198}
199
200void spInterFileContext::GenrateContents()
201{
202    MMemberListT& lst = GetMembers();
203
204    for( size_t f = 0; f != lst.size(); ++f )
205    {
206        wxString& fname = ((spFile*)lst[f])->m_FileName;
207
208        size_t fileNo = GetFileNo( fname );
209
210        wxString& source = m_Contents[ fileNo ];
211
212        wxString result;
213
214        size_t lastKnownPos = 0, // the begining of the file is always "known"
215               lastSavedPos = 0;
216
217        mCurFileNo = fileNo;
218
219        GenerateContextBody( *lst[f], source, result, lastSavedPos, lastKnownPos );
220
221        // the end of file is always known
222
223        lastKnownPos = m_Contents[ fileNo ].length();
224
225        // append the reminder
226
227        DoAppendSourceFragment( source, result,
228                                size_t(lastSavedPos),
229                                size_t(lastKnownPos - lastSavedPos) );
230
231        // replace original contnet with newly generated one
232
233        m_Contents[ fileNo ] = result;
234    }
235}
236
237void spInterFileContext::ParseContents( SourceParserPlugin* pPlugin )
238{
239    mDeletionMarks.erase( mDeletionMarks.begin(), mDeletionMarks.end() );
240
241    RemoveChildren(); // clean up top-level context
242
243    mParser.SetPlugin( pPlugin );
244
245    for( size_t i = 0; i != m_Files.size(); ++i )
246    {
247        wxChar* s = (char*)(m_Contents[i].c_str());
248
249        spFile* pFCtx = mParser.Parse( s, s + m_Contents[i].length() );
250
251        pFCtx->m_FileName = m_Files[i];
252
253        AddMember( pFCtx );
254    }
255}
256
257void spInterFileContext::WriteToFiles()
258{
259    for( size_t i = 0; i != m_Files.size(); ++i )
260    {
261        FILE* fp = fopen( m_Files[i].c_str(), "w+t" );
262
263        if ( fp != NULL )
264        {
265            fwrite( m_Contents[i].c_str(), sizeof(char), m_Contents[i].length(), fp );
266
267            fclose( fp );
268        }
269    }
270}
271
272wxString spInterFileContext::GetBody( spContext* pCtx )
273{
274    wxASSERT( pCtx->PositionIsKnown() ); // DBG:: should be checked by-user code
275
276    wxString& source = m_Contents[ GetFileNoOfContext( *pCtx ) ];
277
278    return wxString( source.c_str() + pCtx->mSrcOffset, pCtx->mContextLength );
279}
280
281wxString spInterFileContext::GetHeader( spContext* pCtx )
282{
283    wxASSERT( pCtx->PositionIsKnown() );   // DBG:: should be checked by-user code
284
285    wxASSERT( pCtx->mHeaderLength != -1 ); // DBG:: -/-
286
287    wxString& source = m_Contents[ GetFileNoOfContext( *pCtx ) ];
288
289    return wxString( source.c_str() + pCtx->mSrcOffset, pCtx->mHeaderLength );
290}
291