Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <cstddef>
30 : : #include <cstdio>
31 : :
32 : : #include <string.h>
33 : : #include <tools/mempool.hxx>
34 : : #include <osl/diagnose.h>
35 : : #include <sfx2/docfile.hxx>
36 : :
37 : : #include "token.hxx"
38 : : #include "tokenarray.hxx"
39 : : #include "reftokenhelper.hxx"
40 : : #include "clipparam.hxx"
41 : : #include "compiler.hxx"
42 : : #include <formula/compiler.hrc>
43 : : #include "rechead.hxx"
44 : : #include "parclass.hxx"
45 : : #include "jumpmatrix.hxx"
46 : : #include "rangeseq.hxx"
47 : : #include "externalrefmgr.hxx"
48 : : #include "document.hxx"
49 : :
50 : : using ::std::vector;
51 : :
52 : : #include <com/sun/star/sheet/ComplexReference.hpp>
53 : : #include <com/sun/star/sheet/ExternalReference.hpp>
54 : : #include <com/sun/star/sheet/ReferenceFlags.hpp>
55 : : #include <com/sun/star/sheet/NameToken.hpp>
56 : :
57 : : using namespace formula;
58 : : using namespace com::sun::star;
59 : :
60 : : namespace
61 : : {
62 : 102 : void lcl_SingleRefToCalc( ScSingleRefData& rRef, const sheet::SingleReference& rAPI )
63 : : {
64 : 102 : rRef.InitFlags();
65 : :
66 : 102 : rRef.nCol = static_cast<SCsCOL>(rAPI.Column);
67 : 102 : rRef.nRow = static_cast<SCsROW>(rAPI.Row);
68 : 102 : rRef.nTab = static_cast<SCsTAB>(rAPI.Sheet);
69 : 102 : rRef.nRelCol = static_cast<SCsCOL>(rAPI.RelativeColumn);
70 : 102 : rRef.nRelRow = static_cast<SCsROW>(rAPI.RelativeRow);
71 : 102 : rRef.nRelTab = static_cast<SCsTAB>(rAPI.RelativeSheet);
72 : :
73 : 102 : rRef.SetColRel( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_RELATIVE ) != 0 );
74 : 102 : rRef.SetRowRel( ( rAPI.Flags & sheet::ReferenceFlags::ROW_RELATIVE ) != 0 );
75 : 102 : rRef.SetTabRel( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_RELATIVE ) != 0 );
76 : 102 : rRef.SetColDeleted( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_DELETED ) != 0 );
77 : 102 : rRef.SetRowDeleted( ( rAPI.Flags & sheet::ReferenceFlags::ROW_DELETED ) != 0 );
78 : 102 : rRef.SetTabDeleted( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_DELETED ) != 0 );
79 : 102 : rRef.SetFlag3D( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_3D ) != 0 );
80 : 102 : rRef.SetRelName( ( rAPI.Flags & sheet::ReferenceFlags::RELATIVE_NAME ) != 0 );
81 : 102 : }
82 : :
83 : 0 : void lcl_ExternalRefToCalc( ScSingleRefData& rRef, const sheet::SingleReference& rAPI )
84 : : {
85 : 0 : rRef.InitFlags();
86 : :
87 : 0 : rRef.nCol = static_cast<SCsCOL>(rAPI.Column);
88 : 0 : rRef.nRow = static_cast<SCsROW>(rAPI.Row);
89 : 0 : rRef.nTab = 0;
90 : 0 : rRef.nRelCol = static_cast<SCsCOL>(rAPI.RelativeColumn);
91 : 0 : rRef.nRelRow = static_cast<SCsROW>(rAPI.RelativeRow);
92 : 0 : rRef.nRelTab = 0;
93 : :
94 : 0 : rRef.SetColRel( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_RELATIVE ) != 0 );
95 : 0 : rRef.SetRowRel( ( rAPI.Flags & sheet::ReferenceFlags::ROW_RELATIVE ) != 0 );
96 : 0 : rRef.SetTabRel( false ); // sheet index must be absolute for external refs
97 : 0 : rRef.SetColDeleted( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_DELETED ) != 0 );
98 : 0 : rRef.SetRowDeleted( ( rAPI.Flags & sheet::ReferenceFlags::ROW_DELETED ) != 0 );
99 : 0 : rRef.SetTabDeleted( false ); // sheet must not be deleted for external refs
100 : 0 : rRef.SetFlag3D( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_3D ) != 0 );
101 : 0 : rRef.SetRelName( false );
102 : 0 : }
103 : : //
104 : : } // namespace
105 : :
106 : : // Align MemPools on 4k boundaries - 64 bytes (4k is a MUST for OS/2)
107 : :
108 : : // Since RawTokens are temporary for the compiler, don't align on 4k and waste memory.
109 : : // ScRawToken size is FixMembers + MAXSTRLEN + ~4 ~= 1036
110 : 51 : IMPL_FIXEDMEMPOOL_NEWDEL( ScRawToken )
111 : : // Some ScDoubleRawToken, FixMembers + sizeof(double) ~= 16
112 : 51 : IMPL_FIXEDMEMPOOL_NEWDEL( ScDoubleRawToken )
113 : :
114 : : // Need a whole bunch of ScSingleRefToken
115 : 51 : IMPL_FIXEDMEMPOOL_NEWDEL( ScSingleRefToken )
116 : : // Need quite a lot of ScDoubleRefToken
117 : 51 : IMPL_FIXEDMEMPOOL_NEWDEL( ScDoubleRefToken )
118 : :
119 : : // --- class ScRawToken -----------------------------------------------------
120 : :
121 : 570 : xub_StrLen ScRawToken::GetStrLen( const sal_Unicode* pStr )
122 : : {
123 [ - + ]: 570 : if ( !pStr )
124 : 0 : return 0;
125 : 570 : register const sal_Unicode* p = pStr;
126 [ + + ]: 4476 : while ( *p )
127 : 3906 : p++;
128 : 570 : return sal::static_int_cast<xub_StrLen>( p - pStr );
129 : : }
130 : :
131 : :
132 : 46122 : void ScRawToken::SetOpCode( OpCode e )
133 : : {
134 : 46122 : eOp = e;
135 [ + - - + : 46122 : switch (eOp)
+ ]
136 : : {
137 : : case ocIf:
138 : 42 : eType = svJump;
139 : 42 : nJump[ 0 ] = 3; // If, Else, Behind
140 : 42 : break;
141 : : case ocChose:
142 : 0 : eType = svJump;
143 : 0 : nJump[ 0 ] = MAXJUMPCOUNT+1;
144 : 0 : break;
145 : : case ocMissing:
146 : 0 : eType = svMissing;
147 : 0 : break;
148 : : case ocSep:
149 : : case ocOpen:
150 : : case ocClose:
151 : : case ocArrayRowSep:
152 : : case ocArrayColSep:
153 : : case ocArrayOpen:
154 : : case ocArrayClose:
155 : 29177 : eType = svSep;
156 : 29177 : break;
157 : : default:
158 : 16903 : eType = svByte;
159 : 16903 : sbyte.cByte = 0;
160 : 16903 : sbyte.bHasForceArray = ScParameterClassification::HasForceArray( eOp);
161 : : }
162 : 46122 : nRefCnt = 0;
163 : 46122 : }
164 : :
165 : 285 : void ScRawToken::SetString( const sal_Unicode* pStr )
166 : : {
167 : 285 : eOp = ocPush;
168 : 285 : eType = svString;
169 [ + - ]: 285 : if ( pStr )
170 : : {
171 : 285 : xub_StrLen nLen = GetStrLen( pStr ) + 1;
172 [ - + ]: 285 : if( nLen > MAXSTRLEN )
173 : 0 : nLen = MAXSTRLEN;
174 : 285 : memcpy( cStr, pStr, GetStrLenBytes( nLen ) );
175 : 285 : cStr[ nLen-1 ] = 0;
176 : : }
177 : : else
178 : 0 : cStr[0] = 0;
179 : 285 : nRefCnt = 0;
180 : 285 : }
181 : :
182 : 1690 : void ScRawToken::SetSingleReference( const ScSingleRefData& rRef )
183 : : {
184 : 1690 : eOp = ocPush;
185 : 1690 : eType = svSingleRef;
186 : : aRef.Ref1 =
187 : 1690 : aRef.Ref2 = rRef;
188 : 1690 : nRefCnt = 0;
189 : 1690 : }
190 : :
191 : 1776 : void ScRawToken::SetDoubleReference( const ScComplexRefData& rRef )
192 : : {
193 : 1776 : eOp = ocPush;
194 : 1776 : eType = svDoubleRef;
195 : 1776 : aRef = rRef;
196 : 1776 : nRefCnt = 0;
197 : 1776 : }
198 : :
199 : 1284 : void ScRawToken::SetDouble(double rVal)
200 : : {
201 : 1284 : eOp = ocPush;
202 : 1284 : eType = svDouble;
203 : 1284 : nValue = rVal;
204 : 1284 : nRefCnt = 0;
205 : 1284 : }
206 : :
207 : 0 : void ScRawToken::SetErrorConstant( sal_uInt16 nErr )
208 : : {
209 : 0 : eOp = ocPush;
210 : 0 : eType = svError;
211 : 0 : nError = nErr;
212 : 0 : nRefCnt = 0;
213 : 0 : }
214 : :
215 : 122 : void ScRawToken::SetName(bool bGlobal, sal_uInt16 nIndex)
216 : : {
217 : 122 : eOp = ocName;
218 : 122 : eType = svIndex;
219 : 122 : nRefCnt = 0;
220 : :
221 : 122 : name.bGlobal = bGlobal;
222 : 122 : name.nIndex = nIndex;
223 : 122 : }
224 : :
225 : 69 : void ScRawToken::SetExternalSingleRef( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef )
226 : : {
227 : 69 : eOp = ocPush;
228 : 69 : eType = svExternalSingleRef;
229 : 69 : nRefCnt = 0;
230 : :
231 : 69 : extref.nFileId = nFileId;
232 : : extref.aRef.Ref1 =
233 : 69 : extref.aRef.Ref2 = rRef;
234 : :
235 : 69 : xub_StrLen n = rTabName.Len();
236 : 69 : memcpy(extref.cTabName, rTabName.GetBuffer(), n*sizeof(sal_Unicode));
237 : 69 : extref.cTabName[n] = 0;
238 : 69 : }
239 : :
240 : 18 : void ScRawToken::SetExternalDoubleRef( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef )
241 : : {
242 : 18 : eOp = ocPush;
243 : 18 : eType = svExternalDoubleRef;
244 : 18 : nRefCnt = 0;
245 : :
246 : 18 : extref.nFileId = nFileId;
247 : 18 : extref.aRef = rRef;
248 : :
249 : 18 : xub_StrLen n = rTabName.Len();
250 : 18 : memcpy(extref.cTabName, rTabName.GetBuffer(), n*sizeof(sal_Unicode));
251 : 18 : extref.cTabName[n] = 0;
252 : 18 : }
253 : :
254 : 0 : void ScRawToken::SetExternalName( sal_uInt16 nFileId, const String& rName )
255 : : {
256 : 0 : eOp = ocPush;
257 : 0 : eType = svExternalName;
258 : 0 : nRefCnt = 0;
259 : :
260 : 0 : extname.nFileId = nFileId;
261 : :
262 : 0 : xub_StrLen n = rName.Len();
263 : 0 : memcpy(extname.cName, rName.GetBuffer(), n*sizeof(sal_Unicode));
264 : 0 : extname.cName[n] = 0;
265 : 0 : }
266 : :
267 : :
268 : :
269 : 0 : void ScRawToken::SetExternal( const sal_Unicode* pStr )
270 : : {
271 : 0 : eOp = ocExternal;
272 : 0 : eType = svExternal;
273 : 0 : xub_StrLen nLen = GetStrLen( pStr ) + 1;
274 [ # # ]: 0 : if( nLen >= MAXSTRLEN )
275 : 0 : nLen = MAXSTRLEN-1;
276 : : // Platz fuer Byte-Parameter lassen!
277 : 0 : memcpy( cStr+1, pStr, GetStrLenBytes( nLen ) );
278 : 0 : cStr[ nLen+1 ] = 0;
279 : 0 : nRefCnt = 0;
280 : 0 : }
281 : :
282 : :
283 : 3136 : bool ScRawToken::IsValidReference() const
284 : : {
285 [ + + + - ]: 3136 : switch (eType)
286 : : {
287 : : case svSingleRef:
288 : 1399 : return aRef.Ref1.Valid();
289 : : case svDoubleRef:
290 : 1650 : return aRef.Valid();
291 : : case svExternalSingleRef:
292 : : case svExternalDoubleRef:
293 : 87 : return true;
294 : : default:
295 : : ; // nothing
296 : : }
297 : 3136 : return false;
298 : : }
299 : :
300 : :
301 : 24 : sal_uInt16 lcl_ScRawTokenOffset()
302 : : {
303 : : // offset of sbyte in ScRawToken
304 : : // offsetof(ScRawToken, sbyte) gives a warning with gcc, because ScRawToken is no POD
305 : :
306 : 24 : ScRawToken aToken;
307 : 24 : return static_cast<sal_uInt16>( reinterpret_cast<char*>(&aToken.sbyte) - reinterpret_cast<char*>(&aToken) );
308 : : }
309 : :
310 : 11457 : ScRawToken* ScRawToken::Clone() const
311 : : {
312 : : ScRawToken* p;
313 [ + + ]: 11457 : if ( eType == svDouble )
314 : : {
315 : 1284 : p = (ScRawToken*) new ScDoubleRawToken;
316 : 1284 : p->eOp = eOp;
317 : 1284 : p->eType = eType;
318 : 1284 : p->nValue = nValue;
319 : : }
320 : : else
321 : : {
322 [ + + ][ + - ]: 10173 : static sal_uInt16 nOffset = lcl_ScRawTokenOffset(); // offset of sbyte
323 : 10173 : sal_uInt16 n = nOffset;
324 : :
325 [ + + - - : 10173 : switch( eType )
+ + - + +
- + - - ]
326 : : {
327 : 4235 : case svSep: break;
328 : 1939 : case svByte: n += sizeof(ScRawToken::sbyte); break;
329 : 0 : case svDouble: n += sizeof(double); break;
330 : 0 : case svError: n += sizeof(nError); break;
331 : 285 : case svString: n = sal::static_int_cast<sal_uInt16>( n + GetStrLenBytes( cStr ) + GetStrLenBytes( 1 ) ); break;
332 : : case svSingleRef:
333 : 3466 : case svDoubleRef: n += sizeof(aRef); break;
334 : 0 : case svMatrix: n += sizeof(ScMatrix*); break;
335 : 122 : case svIndex: n += sizeof(name); break;
336 : 39 : case svJump: n += nJump[ 0 ] * 2 + 2; break;
337 : 0 : case svExternal: n = sal::static_int_cast<sal_uInt16>( n + GetStrLenBytes( cStr+1 ) + GetStrLenBytes( 2 ) ); break;
338 : :
339 : : // external references
340 : : case svExternalSingleRef:
341 : 87 : case svExternalDoubleRef: n += sizeof(extref); break;
342 : 0 : case svExternalName: n += sizeof(extname); break;
343 : : default:
344 : : {
345 : : OSL_TRACE( "unknown ScRawToken::Clone() type %d", int(eType));
346 : : }
347 : : }
348 : 10173 : p = (ScRawToken*) new sal_uInt8[ n ];
349 : 10173 : memcpy( p, this, n * sizeof(sal_uInt8) );
350 : : }
351 : 11457 : p->nRefCnt = 0;
352 : 11457 : p->bRaw = false;
353 : 11457 : return p;
354 : : }
355 : :
356 : :
357 : 51366 : FormulaToken* ScRawToken::CreateToken() const
358 : : {
359 : : #if OSL_DEBUG_LEVEL > 1
360 : : #define IF_NOT_OPCODE_ERROR(o,c) if (eOp!=o) OSL_TRACE( #c "::ctor: OpCode %d lost, converted to " #o "; maybe inherit from FormulaToken instead!", int(eOp))
361 : : #else
362 : : #define IF_NOT_OPCODE_ERROR(o,c)
363 : : #endif
364 [ + + + + : 51366 : switch ( GetType() )
+ - + + +
- + - - -
+ - - - ]
365 : : {
366 : : case svByte :
367 [ + - ]: 16903 : return new FormulaByteToken( eOp, sbyte.cByte, sbyte.bHasForceArray );
368 : : case svDouble :
369 : : IF_NOT_OPCODE_ERROR( ocPush, FormulaDoubleToken);
370 [ + - ]: 1284 : return new FormulaDoubleToken( nValue );
371 : : case svString :
372 [ + + ]: 285 : if (eOp == ocPush)
373 [ + - ][ + - ]: 258 : return new FormulaStringToken( rtl::OUString( cStr ) );
[ + - ][ + - ]
374 : : else
375 [ + - ][ + - ]: 27 : return new FormulaStringOpToken( eOp, rtl::OUString( cStr ) );
[ + - ][ + - ]
376 : : case svSingleRef :
377 [ + - ]: 1690 : if (eOp == ocPush)
378 [ + - ]: 1690 : return new ScSingleRefToken( aRef.Ref1 );
379 : : else
380 [ # # ]: 0 : return new ScSingleRefToken( aRef.Ref1, eOp );
381 : : case svDoubleRef :
382 [ + - ]: 1776 : if (eOp == ocPush)
383 [ + - ]: 1776 : return new ScDoubleRefToken( aRef );
384 : : else
385 [ # # ]: 0 : return new ScDoubleRefToken( aRef, eOp );
386 : : case svMatrix :
387 : : IF_NOT_OPCODE_ERROR( ocPush, ScMatrixToken);
388 [ # # ][ # # ]: 0 : return new ScMatrixToken( pMat );
389 : : case svIndex :
390 [ + - ]: 122 : return new FormulaIndexToken( eOp, name.nIndex, name.bGlobal);
391 : : case svExternalSingleRef:
392 : : {
393 : 69 : rtl::OUString aTabName(extref.cTabName);
394 [ + - ][ + - ]: 69 : return new ScExternalSingleRefToken(extref.nFileId, aTabName, extref.aRef.Ref1);
[ + - ][ + - ]
395 : : }
396 : : case svExternalDoubleRef:
397 : : {
398 : 18 : rtl::OUString aTabName(extref.cTabName);
399 [ + - ][ + - ]: 18 : return new ScExternalDoubleRefToken(extref.nFileId, aTabName, extref.aRef);
[ + - ][ + - ]
400 : : }
401 : : case svExternalName:
402 : : {
403 : 0 : rtl::OUString aName(extname.cName);
404 [ # # ][ # # ]: 0 : return new ScExternalNameToken( extname.nFileId, aName );
[ # # ][ # # ]
405 : : }
406 : : case svJump :
407 [ + - ]: 42 : return new FormulaJumpToken( eOp, (short*) nJump );
408 : : case svExternal :
409 [ # # ][ # # ]: 0 : return new FormulaExternalToken( eOp, sbyte.cByte, rtl::OUString( cStr+1 ) );
[ # # ][ # # ]
410 : : case svFAP :
411 [ # # ]: 0 : return new FormulaFAPToken( eOp, sbyte.cByte, NULL );
412 : : case svMissing :
413 : : IF_NOT_OPCODE_ERROR( ocMissing, FormulaMissingToken);
414 [ # # ]: 0 : return new FormulaMissingToken;
415 : : case svSep :
416 : 29177 : return new FormulaToken( svSep,eOp );
417 : : case svError :
418 [ # # ]: 0 : return new FormulaErrorToken( nError );
419 : : case svUnknown :
420 [ # # ]: 0 : return new FormulaUnknownToken( eOp );
421 : : default:
422 : : {
423 : : OSL_TRACE( "unknown ScRawToken::CreateToken() type %d", int(GetType()));
424 [ # # ]: 51366 : return new FormulaUnknownToken( ocBad );
425 : : }
426 : : }
427 : : #undef IF_NOT_OPCODE_ERROR
428 : : }
429 : :
430 : :
431 : 11457 : void ScRawToken::Delete()
432 : : {
433 [ - + ]: 11457 : if ( bRaw )
434 [ # # ]: 0 : delete this; // FixedMemPool ScRawToken
435 : : else
436 : : { // created per Clone
437 [ + + ]: 11457 : switch ( eType )
438 : : {
439 : : case svDouble :
440 : 1284 : delete (ScDoubleRawToken*) this; // FixedMemPool ScDoubleRawToken
441 : 1284 : break;
442 : : default:
443 [ + - ]: 10173 : delete [] (sal_uInt8*) this;
444 : : }
445 : : }
446 : 11457 : }
447 : :
448 : :
449 : : // --- class ScToken --------------------------------------------------------
450 : :
451 : 0 : ScSingleRefData lcl_ScToken_InitSingleRef()
452 : : {
453 : : ScSingleRefData aRef;
454 : 0 : aRef.InitAddress( ScAddress() );
455 : 0 : return aRef;
456 : : }
457 : :
458 : 0 : ScComplexRefData lcl_ScToken_InitDoubleRef()
459 : : {
460 : : ScComplexRefData aRef;
461 : 0 : aRef.Ref1 = lcl_ScToken_InitSingleRef();
462 : 0 : aRef.Ref2 = aRef.Ref1;
463 : 0 : return aRef;
464 : : }
465 : :
466 : 42936 : ScToken::~ScToken()
467 : : {
468 [ - + ]: 42936 : }
469 : :
470 : : // TextEqual: if same formula entered (for optimization in sort)
471 : 8 : bool ScToken::TextEqual( const FormulaToken& _rToken ) const
472 : : {
473 [ - + ][ # # ]: 8 : if ( eType == svSingleRef || eType == svDoubleRef )
474 : : {
475 : : // in relative Refs only compare relative parts
476 : :
477 [ + - ][ - + ]: 8 : if ( eType != _rToken.GetType() || GetOpCode() != _rToken.GetOpCode() )
[ - + ]
478 : 0 : return false;
479 : :
480 : 8 : const ScToken& rToken = static_cast<const ScToken&>(_rToken);
481 : : ScComplexRefData aTemp1;
482 [ + - ]: 8 : if ( eType == svSingleRef )
483 : : {
484 [ + - ]: 8 : aTemp1.Ref1 = GetSingleRef();
485 : 8 : aTemp1.Ref2 = aTemp1.Ref1;
486 : : }
487 : : else
488 [ # # ]: 0 : aTemp1 = GetDoubleRef();
489 : :
490 : : ScComplexRefData aTemp2;
491 [ + - ]: 8 : if ( rToken.eType == svSingleRef )
492 : : {
493 [ + - ]: 8 : aTemp2.Ref1 = rToken.GetSingleRef();
494 : 8 : aTemp2.Ref2 = aTemp2.Ref1;
495 : : }
496 : : else
497 [ # # ]: 0 : aTemp2 = rToken.GetDoubleRef();
498 : :
499 : 8 : ScAddress aPos;
500 [ + - ]: 8 : aTemp1.SmartRelAbs(aPos);
501 [ + - ]: 8 : aTemp2.SmartRelAbs(aPos);
502 : :
503 : : // memcmp doesn't work because of the alignment byte after bFlags.
504 : : // After SmartRelAbs only absolute parts have to be compared.
505 : : return aTemp1.Ref1.nCol == aTemp2.Ref1.nCol &&
506 : : aTemp1.Ref1.nRow == aTemp2.Ref1.nRow &&
507 : : aTemp1.Ref1.nTab == aTemp2.Ref1.nTab &&
508 : : aTemp1.Ref1.bFlags == aTemp2.Ref1.bFlags &&
509 : : aTemp1.Ref2.nCol == aTemp2.Ref2.nCol &&
510 : : aTemp1.Ref2.nRow == aTemp2.Ref2.nRow &&
511 : : aTemp1.Ref2.nTab == aTemp2.Ref2.nTab &&
512 [ + - ][ + - ]: 8 : aTemp1.Ref2.bFlags == aTemp2.Ref2.bFlags;
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
513 : : }
514 : : else
515 : 8 : return *this == _rToken; // else normal operator==
516 : : }
517 : :
518 : :
519 : 0 : bool ScToken::Is3DRef() const
520 : : {
521 [ # # # ]: 0 : switch ( eType )
522 : : {
523 : : case svDoubleRef :
524 [ # # ]: 0 : if ( GetSingleRef2().IsFlag3D() )
525 : 0 : return true;
526 : : //! fallthru
527 : : case svSingleRef :
528 [ # # ]: 0 : if ( GetSingleRef().IsFlag3D() )
529 : 0 : return true;
530 : 0 : break;
531 : : default:
532 : : {
533 : : // added to avoid warnings
534 : : }
535 : : }
536 : 0 : return false;
537 : : }
538 : :
539 : 0 : FormulaTokenRef ScToken::ExtendRangeReference( FormulaToken & rTok1, FormulaToken & rTok2,
540 : : const ScAddress & rPos, bool bReuseDoubleRef )
541 : : {
542 : :
543 : : StackVar sv1, sv2;
544 : : // Doing a RangeOp with RefList is probably utter nonsense, but Xcl
545 : : // supports it, so do we.
546 [ # # ][ # # ]: 0 : if (((sv1 = rTok1.GetType()) != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList &&
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
547 : : sv1 != svExternalSingleRef && sv1 != svExternalDoubleRef ) ||
548 : : ((sv2 = rTok2.GetType()) != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList))
549 : 0 : return NULL;
550 : :
551 : 0 : ScToken *p1 = static_cast<ScToken*>(&rTok1);
552 : 0 : ScToken *p2 = static_cast<ScToken*>(&rTok2);
553 : :
554 : 0 : ScTokenRef xRes;
555 : 0 : bool bExternal = (sv1 == svExternalSingleRef);
556 [ # # ][ # # ]: 0 : if ((sv1 == svSingleRef || bExternal) && sv2 == svSingleRef)
[ # # ]
557 : : {
558 : : // Range references like Sheet1.A1:A2 are generalized and built by
559 : : // first creating a DoubleRef from the first SingleRef, effectively
560 : : // generating Sheet1.A1:A1, and then extending that with A2 as if
561 : : // Sheet1.A1:A1:A2 was encountered, so the mechanisms to adjust the
562 : : // references apply as well.
563 : :
564 : : /* Given the current structure of external references an external
565 : : * reference can only be extended if the second reference does not
566 : : * point to a different sheet. 'file'#Sheet1.A1:A2 is ok,
567 : : * 'file'#Sheet1.A1:Sheet2.A2 is not. Since we can't determine from a
568 : : * svSingleRef whether the sheet would be different from the one given
569 : : * in the external reference, we have to bail out if there is any sheet
570 : : * specified. NOTE: Xcl does handle external 3D references as in
571 : : * '[file]Sheet1:Sheet2'!A1:A2
572 : : *
573 : : * FIXME: For OOo syntax be smart and remember an external singleref
574 : : * encountered and if followed by ocRange and singleref, create an
575 : : * external singleref for the second singleref. Both could then be
576 : : * merged here. For Xcl syntax already parse an external range
577 : : * reference entirely, cumbersome. */
578 : :
579 [ # # ]: 0 : const ScSingleRefData& rRef2 = p2->GetSingleRef();
580 [ # # ][ # # ]: 0 : if (bExternal && rRef2.IsFlag3D())
[ # # ]
581 : 0 : return NULL;
582 : :
583 : : ScComplexRefData aRef;
584 [ # # ]: 0 : aRef.Ref1 = aRef.Ref2 = p1->GetSingleRef();
585 : 0 : aRef.Ref2.SetFlag3D( false);
586 [ # # ]: 0 : aRef.Extend( rRef2, rPos);
587 [ # # ]: 0 : if (bExternal)
588 [ # # ][ # # ]: 0 : xRes = new ScExternalDoubleRefToken( p1->GetIndex(), p1->GetString(), aRef);
[ # # ][ # # ]
[ # # ]
589 : : else
590 [ # # ][ # # ]: 0 : xRes = new ScDoubleRefToken( aRef);
[ # # ]
591 : : }
592 : : else
593 : : {
594 : 0 : bExternal |= (sv1 == svExternalDoubleRef);
595 : 0 : const ScRefList* pRefList = NULL;
596 [ # # ]: 0 : if (sv1 == svDoubleRef)
597 : : {
598 [ # # ][ # # ]: 0 : xRes = (bReuseDoubleRef && p1->GetRef() == 1 ? p1 : static_cast<ScToken*>(p1->Clone()));
[ # # ][ # # ]
599 : 0 : sv1 = svUnknown; // mark as handled
600 : : }
601 [ # # ]: 0 : else if (sv2 == svDoubleRef)
602 : : {
603 [ # # ][ # # ]: 0 : xRes = (bReuseDoubleRef && p2->GetRef() == 1 ? p2 : static_cast<ScToken*>(p2->Clone()));
[ # # ][ # # ]
604 : 0 : sv2 = svUnknown; // mark as handled
605 : : }
606 [ # # ]: 0 : else if (sv1 == svRefList)
607 [ # # ]: 0 : pRefList = p1->GetRefList();
608 [ # # ]: 0 : else if (sv2 == svRefList)
609 [ # # ]: 0 : pRefList = p2->GetRefList();
610 [ # # ]: 0 : if (pRefList)
611 : : {
612 [ # # ]: 0 : if (!pRefList->size())
613 : 0 : return NULL;
614 [ # # ]: 0 : if (bExternal)
615 : 0 : return NULL; // external reference list not possible
616 [ # # ][ # # ]: 0 : xRes = new ScDoubleRefToken( (*pRefList)[0] );
[ # # ]
617 : : }
618 [ # # ]: 0 : if (!xRes)
619 : 0 : return NULL; // shouldn't happen..
620 : 0 : StackVar sv[2] = { sv1, sv2 };
621 : 0 : ScToken* pt[2] = { p1, p2 };
622 [ # # ]: 0 : ScComplexRefData& rRef = xRes->GetDoubleRef();
623 [ # # ]: 0 : for (size_t i=0; i<2; ++i)
624 : : {
625 [ # # # # : 0 : switch (sv[i])
# # ]
626 : : {
627 : : case svSingleRef:
628 [ # # ][ # # ]: 0 : rRef.Extend( pt[i]->GetSingleRef(), rPos);
629 : 0 : break;
630 : : case svDoubleRef:
631 [ # # ][ # # ]: 0 : rRef.Extend( pt[i]->GetDoubleRef(), rPos);
632 : 0 : break;
633 : : case svRefList:
634 : : {
635 [ # # ]: 0 : const ScRefList* p = pt[i]->GetRefList();
636 [ # # ]: 0 : if (!p->size())
637 : 0 : return NULL;
638 : 0 : ScRefList::const_iterator it( p->begin());
639 : 0 : ScRefList::const_iterator end( p->end());
640 [ # # ][ # # ]: 0 : for ( ; it != end; ++it)
641 : : {
642 [ # # ]: 0 : rRef.Extend( *it, rPos);
643 : : }
644 : : }
645 : 0 : break;
646 : : case svExternalSingleRef:
647 [ # # ][ # # ]: 0 : if (rRef.Ref1.IsFlag3D() || rRef.Ref2.IsFlag3D())
[ # # ]
648 : 0 : return NULL; // no other sheets with external refs
649 : : else
650 [ # # ][ # # ]: 0 : rRef.Extend( pt[i]->GetSingleRef(), rPos);
651 : 0 : break;
652 : : case svExternalDoubleRef:
653 [ # # ][ # # ]: 0 : if (rRef.Ref1.IsFlag3D() || rRef.Ref2.IsFlag3D())
[ # # ]
654 : 0 : return NULL; // no other sheets with external refs
655 : : else
656 [ # # ][ # # ]: 0 : rRef.Extend( pt[i]->GetDoubleRef(), rPos);
657 : 0 : break;
658 : : default:
659 : : ; // nothing, prevent compiler warning
660 : : }
661 : : }
662 : : }
663 [ # # ]: 0 : return FormulaTokenRef(xRes.get());
664 : : }
665 : :
666 : 0 : const ScSingleRefData& ScToken::GetSingleRef() const
667 : : {
668 : : OSL_FAIL( "ScToken::GetSingleRef: virtual dummy called" );
669 [ # # ][ # # ]: 0 : static ScSingleRefData aDummySingleRef = lcl_ScToken_InitSingleRef();
670 : 0 : return aDummySingleRef;
671 : : }
672 : :
673 : 0 : ScSingleRefData& ScToken::GetSingleRef()
674 : : {
675 : : OSL_FAIL( "ScToken::GetSingleRef: virtual dummy called" );
676 [ # # ][ # # ]: 0 : static ScSingleRefData aDummySingleRef = lcl_ScToken_InitSingleRef();
677 : 0 : return aDummySingleRef;
678 : : }
679 : :
680 : 0 : const ScComplexRefData& ScToken::GetDoubleRef() const
681 : : {
682 : : OSL_FAIL( "ScToken::GetDoubleRef: virtual dummy called" );
683 [ # # ][ # # ]: 0 : static ScComplexRefData aDummyDoubleRef = lcl_ScToken_InitDoubleRef();
684 : 0 : return aDummyDoubleRef;
685 : : }
686 : :
687 : 0 : ScComplexRefData& ScToken::GetDoubleRef()
688 : : {
689 : : OSL_FAIL( "ScToken::GetDoubleRef: virtual dummy called" );
690 [ # # ][ # # ]: 0 : static ScComplexRefData aDummyDoubleRef = lcl_ScToken_InitDoubleRef();
691 : 0 : return aDummyDoubleRef;
692 : : }
693 : :
694 : 0 : const ScSingleRefData& ScToken::GetSingleRef2() const
695 : : {
696 : : OSL_FAIL( "ScToken::GetSingleRef2: virtual dummy called" );
697 [ # # ][ # # ]: 0 : static ScSingleRefData aDummySingleRef = lcl_ScToken_InitSingleRef();
698 : 0 : return aDummySingleRef;
699 : : }
700 : :
701 : 0 : ScSingleRefData& ScToken::GetSingleRef2()
702 : : {
703 : : OSL_FAIL( "ScToken::GetSingleRef2: virtual dummy called" );
704 [ # # ][ # # ]: 0 : static ScSingleRefData aDummySingleRef = lcl_ScToken_InitSingleRef();
705 : 0 : return aDummySingleRef;
706 : : }
707 : :
708 : 0 : void ScToken::CalcAbsIfRel( const ScAddress& /* rPos */ )
709 : : {
710 : : OSL_FAIL( "ScToken::CalcAbsIfRel: virtual dummy called" );
711 : 0 : }
712 : :
713 : 0 : void ScToken::CalcRelFromAbs( const ScAddress& /* rPos */ )
714 : : {
715 : : OSL_FAIL( "ScToken::CalcRelFromAbs: virtual dummy called" );
716 : 0 : }
717 : :
718 : 0 : const ScMatrix* ScToken::GetMatrix() const
719 : : {
720 : : OSL_FAIL( "ScToken::GetMatrix: virtual dummy called" );
721 : 0 : return NULL;
722 : : }
723 : :
724 : 0 : ScMatrix* ScToken::GetMatrix()
725 : : {
726 : : OSL_FAIL( "ScToken::GetMatrix: virtual dummy called" );
727 : 0 : return NULL;
728 : : }
729 : :
730 : :
731 : 0 : ScJumpMatrix* ScToken::GetJumpMatrix() const
732 : : {
733 : : OSL_FAIL( "ScToken::GetJumpMatrix: virtual dummy called" );
734 : 0 : return NULL;
735 : : }
736 : 0 : const ScRefList* ScToken::GetRefList() const
737 : : {
738 : : OSL_FAIL( "ScToken::GetRefList: virtual dummy called" );
739 : 0 : return NULL;
740 : : }
741 : :
742 : 0 : ScRefList* ScToken::GetRefList()
743 : : {
744 : : OSL_FAIL( "ScToken::GetRefList: virtual dummy called" );
745 : 0 : return NULL;
746 : : }
747 : : // ==========================================================================
748 : : // real implementations of virtual functions
749 : : // --------------------------------------------------------------------------
750 : :
751 : :
752 : :
753 : :
754 : 1347 : const ScSingleRefData& ScSingleRefToken::GetSingleRef() const { return aSingleRef; }
755 : 45392 : ScSingleRefData& ScSingleRefToken::GetSingleRef() { return aSingleRef; }
756 : 495 : void ScSingleRefToken::CalcAbsIfRel( const ScAddress& rPos )
757 : 495 : { aSingleRef.CalcAbsIfRel( rPos ); }
758 : 214 : void ScSingleRefToken::CalcRelFromAbs( const ScAddress& rPos )
759 : 214 : { aSingleRef.CalcRelFromAbs( rPos ); }
760 : 10 : bool ScSingleRefToken::operator==( const FormulaToken& r ) const
761 : : {
762 [ + - ][ + + ]: 10 : return FormulaToken::operator==( r ) && aSingleRef == static_cast<const ScToken&>(r).GetSingleRef();
763 : : }
764 : :
765 : :
766 : 51 : const ScSingleRefData& ScDoubleRefToken::GetSingleRef() const { return aDoubleRef.Ref1; }
767 : 5878 : ScSingleRefData& ScDoubleRefToken::GetSingleRef() { return aDoubleRef.Ref1; }
768 : 1756 : const ScComplexRefData& ScDoubleRefToken::GetDoubleRef() const { return aDoubleRef; }
769 : 39495 : ScComplexRefData& ScDoubleRefToken::GetDoubleRef() { return aDoubleRef; }
770 : 36 : const ScSingleRefData& ScDoubleRefToken::GetSingleRef2() const { return aDoubleRef.Ref2; }
771 : 0 : ScSingleRefData& ScDoubleRefToken::GetSingleRef2() { return aDoubleRef.Ref2; }
772 : 5823 : void ScDoubleRefToken::CalcAbsIfRel( const ScAddress& rPos )
773 : 5823 : { aDoubleRef.CalcAbsIfRel( rPos ); }
774 : 0 : void ScDoubleRefToken::CalcRelFromAbs( const ScAddress& rPos )
775 : 0 : { aDoubleRef.CalcRelFromAbs( rPos ); }
776 : 0 : bool ScDoubleRefToken::operator==( const FormulaToken& r ) const
777 : : {
778 [ # # ][ # # ]: 0 : return FormulaToken::operator==( r ) && aDoubleRef == static_cast<const ScToken&>(r).GetDoubleRef();
779 : : }
780 : :
781 : :
782 : 0 : const ScRefList* ScRefListToken::GetRefList() const { return &aRefList; }
783 : 0 : ScRefList* ScRefListToken::GetRefList() { return &aRefList; }
784 : 0 : void ScRefListToken::CalcAbsIfRel( const ScAddress& rPos )
785 : : {
786 [ # # ][ # # ]: 0 : for (ScRefList::iterator it( aRefList.begin()); it != aRefList.end(); ++it)
787 [ # # ]: 0 : (*it).CalcAbsIfRel( rPos);
788 : 0 : }
789 : 0 : void ScRefListToken::CalcRelFromAbs( const ScAddress& rPos )
790 : : {
791 [ # # ][ # # ]: 0 : for (ScRefList::iterator it( aRefList.begin()); it != aRefList.end(); ++it)
792 [ # # ]: 0 : (*it).CalcRelFromAbs( rPos);
793 : 0 : }
794 : 0 : bool ScRefListToken::operator==( const FormulaToken& r ) const
795 : : {
796 [ # # ][ # # ]: 0 : return FormulaToken::operator==( r ) && &aRefList == static_cast<const ScToken&>(r).GetRefList();
797 : : }
798 : :
799 : :
800 : 6 : const ScMatrix* ScMatrixToken::GetMatrix() const { return pMatrix.get(); }
801 : 249 : ScMatrix* ScMatrixToken::GetMatrix() { return pMatrix.get(); }
802 : 0 : bool ScMatrixToken::operator==( const FormulaToken& r ) const
803 : : {
804 [ # # ][ # # ]: 0 : return FormulaToken::operator==( r ) && pMatrix == static_cast<const ScToken&>(r).GetMatrix();
805 : : }
806 : :
807 : : // ============================================================================
808 : :
809 : 80 : ScExternalSingleRefToken::ScExternalSingleRefToken( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& r ) :
810 : : ScToken( svExternalSingleRef, ocPush),
811 : : mnFileId(nFileId),
812 : : maTabName(rTabName),
813 [ + - ]: 80 : maSingleRef(r)
814 : : {
815 : 80 : }
816 : :
817 : 4 : ScExternalSingleRefToken::ScExternalSingleRefToken( const ScExternalSingleRefToken& r ) :
818 : : ScToken(r),
819 : : mnFileId(r.mnFileId),
820 : : maTabName(r.maTabName),
821 [ + - ]: 4 : maSingleRef(r.maSingleRef)
822 : : {
823 : 4 : }
824 : :
825 [ + - ]: 2 : ScExternalSingleRefToken::~ScExternalSingleRefToken()
826 : : {
827 [ - + ]: 4 : }
828 : :
829 : 80 : sal_uInt16 ScExternalSingleRefToken::GetIndex() const
830 : : {
831 : 80 : return mnFileId;
832 : : }
833 : :
834 : 80 : const String& ScExternalSingleRefToken::GetString() const
835 : : {
836 : 80 : return maTabName;
837 : : }
838 : :
839 : 0 : const ScSingleRefData& ScExternalSingleRefToken::GetSingleRef() const
840 : : {
841 : 0 : return maSingleRef;
842 : : }
843 : :
844 : 183 : ScSingleRefData& ScExternalSingleRefToken::GetSingleRef()
845 : : {
846 : 183 : return maSingleRef;
847 : : }
848 : :
849 : 0 : void ScExternalSingleRefToken::CalcAbsIfRel( const ScAddress& rPos )
850 : : {
851 : 0 : maSingleRef.CalcAbsIfRel( rPos );
852 : 0 : }
853 : :
854 : 0 : void ScExternalSingleRefToken::CalcRelFromAbs( const ScAddress& rPos )
855 : : {
856 : 0 : maSingleRef.CalcRelFromAbs( rPos );
857 : 0 : }
858 : :
859 : 0 : bool ScExternalSingleRefToken::operator ==( const FormulaToken& r ) const
860 : : {
861 [ # # ]: 0 : if (!FormulaToken::operator==(r))
862 : 0 : return false;
863 : :
864 [ # # ]: 0 : if (mnFileId != r.GetIndex())
865 : 0 : return false;
866 : :
867 [ # # ]: 0 : if (maTabName != r.GetString())
868 : 0 : return false;
869 : :
870 : 0 : return maSingleRef == static_cast<const ScToken&>(r).GetSingleRef();
871 : : }
872 : :
873 : : // ============================================================================
874 : :
875 : 18 : ScExternalDoubleRefToken::ScExternalDoubleRefToken( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& r ) :
876 : : ScToken( svExternalDoubleRef, ocPush),
877 : : mnFileId(nFileId),
878 : : maTabName(rTabName),
879 [ + - ]: 18 : maDoubleRef(r)
880 : : {
881 : 18 : }
882 : :
883 : 0 : ScExternalDoubleRefToken::ScExternalDoubleRefToken( const ScExternalDoubleRefToken& r ) :
884 : : ScToken(r),
885 : : mnFileId(r.mnFileId),
886 : : maTabName(r.maTabName),
887 [ # # ]: 0 : maDoubleRef(r.maDoubleRef)
888 : : {
889 : 0 : }
890 : :
891 [ + - ]: 18 : ScExternalDoubleRefToken::~ScExternalDoubleRefToken()
892 : : {
893 [ - + ]: 36 : }
894 : :
895 : 18 : sal_uInt16 ScExternalDoubleRefToken::GetIndex() const
896 : : {
897 : 18 : return mnFileId;
898 : : }
899 : :
900 : 18 : const String& ScExternalDoubleRefToken::GetString() const
901 : : {
902 : 18 : return maTabName;
903 : : }
904 : :
905 : 0 : const ScSingleRefData& ScExternalDoubleRefToken::GetSingleRef() const
906 : : {
907 : 0 : return maDoubleRef.Ref1;
908 : : }
909 : :
910 : 36 : ScSingleRefData& ScExternalDoubleRefToken::GetSingleRef()
911 : : {
912 : 36 : return maDoubleRef.Ref1;
913 : : }
914 : :
915 : 0 : const ScSingleRefData& ScExternalDoubleRefToken::GetSingleRef2() const
916 : : {
917 : 0 : return maDoubleRef.Ref2;
918 : : }
919 : :
920 : 0 : ScSingleRefData& ScExternalDoubleRefToken::GetSingleRef2()
921 : : {
922 : 0 : return maDoubleRef.Ref2;
923 : : }
924 : :
925 : 0 : const ScComplexRefData& ScExternalDoubleRefToken::GetDoubleRef() const
926 : : {
927 : 0 : return maDoubleRef;
928 : : }
929 : :
930 : 18 : ScComplexRefData& ScExternalDoubleRefToken::GetDoubleRef()
931 : : {
932 : 18 : return maDoubleRef;
933 : : }
934 : :
935 : 0 : void ScExternalDoubleRefToken::CalcAbsIfRel( const ScAddress& rPos )
936 : : {
937 : 0 : maDoubleRef.CalcAbsIfRel( rPos );
938 : 0 : }
939 : :
940 : 0 : void ScExternalDoubleRefToken::CalcRelFromAbs( const ScAddress& rPos )
941 : : {
942 : 0 : maDoubleRef.CalcRelFromAbs( rPos );
943 : 0 : }
944 : :
945 : 0 : bool ScExternalDoubleRefToken::operator ==( const FormulaToken& r ) const
946 : : {
947 [ # # ]: 0 : if (!ScToken::operator==(r))
948 : 0 : return false;
949 : :
950 [ # # ]: 0 : if (mnFileId != r.GetIndex())
951 : 0 : return false;
952 : :
953 [ # # ]: 0 : if (maTabName != r.GetString())
954 : 0 : return false;
955 : :
956 : 0 : return maDoubleRef == static_cast<const ScToken&>(r).GetDoubleRef();
957 : : }
958 : :
959 : : // ============================================================================
960 : :
961 : 0 : ScExternalNameToken::ScExternalNameToken( sal_uInt16 nFileId, const String& rName ) :
962 : : ScToken( svExternalName, ocPush),
963 : : mnFileId(nFileId),
964 [ # # ]: 0 : maName(rName)
965 : : {
966 : 0 : }
967 : :
968 : 0 : ScExternalNameToken::ScExternalNameToken( const ScExternalNameToken& r ) :
969 : : ScToken(r),
970 : : mnFileId(r.mnFileId),
971 [ # # ]: 0 : maName(r.maName)
972 : : {
973 : 0 : }
974 : :
975 [ # # ][ # # ]: 0 : ScExternalNameToken::~ScExternalNameToken() {}
976 : :
977 : 0 : sal_uInt16 ScExternalNameToken::GetIndex() const
978 : : {
979 : 0 : return mnFileId;
980 : : }
981 : :
982 : 0 : const String& ScExternalNameToken::GetString() const
983 : : {
984 : 0 : return maName;
985 : : }
986 : :
987 : 0 : bool ScExternalNameToken::operator==( const FormulaToken& r ) const
988 : : {
989 [ # # ]: 0 : if ( !FormulaToken::operator==(r) )
990 : 0 : return false;
991 : :
992 [ # # ]: 0 : if (mnFileId != r.GetIndex())
993 : 0 : return false;
994 : :
995 : 0 : xub_StrLen nLen = maName.Len();
996 : 0 : const String& rName = r.GetString();
997 [ # # ]: 0 : if (nLen != rName.Len())
998 : 0 : return false;
999 : :
1000 : 0 : const sal_Unicode* p1 = maName.GetBuffer();
1001 : 0 : const sal_Unicode* p2 = rName.GetBuffer();
1002 [ # # ]: 0 : for (xub_StrLen j = 0; j < nLen; ++j)
1003 : : {
1004 [ # # ]: 0 : if (p1[j] != p2[j])
1005 : 0 : return false;
1006 : : }
1007 : 0 : return true;
1008 : : }
1009 : :
1010 : : // ============================================================================
1011 : :
1012 : 0 : ScJumpMatrix* ScJumpMatrixToken::GetJumpMatrix() const { return pJumpMatrix; }
1013 : 0 : bool ScJumpMatrixToken::operator==( const FormulaToken& r ) const
1014 : : {
1015 [ # # ][ # # ]: 0 : return FormulaToken::operator==( r ) && pJumpMatrix == static_cast<const ScToken&>(r).GetJumpMatrix();
1016 : : }
1017 : 0 : ScJumpMatrixToken::~ScJumpMatrixToken()
1018 : : {
1019 [ # # ][ # # ]: 0 : delete pJumpMatrix;
1020 [ # # ]: 0 : }
1021 : :
1022 : 0 : double ScEmptyCellToken::GetDouble() const { return 0.0; }
1023 : 0 : const String & ScEmptyCellToken::GetString() const
1024 : : {
1025 [ # # ][ # # ]: 0 : static String aDummyString;
[ # # ][ # # ]
1026 : 0 : return aDummyString;
1027 : : }
1028 : 0 : bool ScEmptyCellToken::operator==( const FormulaToken& r ) const
1029 : : {
1030 : 0 : return FormulaToken::operator==( r ) &&
1031 : 0 : bInherited == static_cast< const ScEmptyCellToken & >(r).IsInherited() &&
1032 [ # # ]: 0 : bDisplayedAsString == static_cast< const ScEmptyCellToken & >(r).IsDisplayedAsString();
[ # # # # ]
1033 : : }
1034 : :
1035 : :
1036 : 0 : double ScMatrixCellResultToken::GetDouble() const { return xUpperLeft->GetDouble(); }
1037 : 0 : const String & ScMatrixCellResultToken::GetString() const { return xUpperLeft->GetString(); }
1038 : 425 : const ScMatrix* ScMatrixCellResultToken::GetMatrix() const { return xMatrix.get(); }
1039 : : // Non-const GetMatrix() is private and unused but must be implemented to
1040 : : // satisfy vtable linkage.
1041 : 0 : ScMatrix* ScMatrixCellResultToken::GetMatrix()
1042 : : {
1043 : 0 : return const_cast<ScMatrix*>(xMatrix.get());
1044 : : }
1045 : 0 : bool ScMatrixCellResultToken::operator==( const FormulaToken& r ) const
1046 : : {
1047 : 0 : return FormulaToken::operator==( r ) &&
1048 : 0 : xUpperLeft == static_cast<const ScMatrixCellResultToken &>(r).xUpperLeft &&
1049 [ # # ]: 0 : xMatrix == static_cast<const ScMatrixCellResultToken &>(r).xMatrix;
[ # # # # ]
1050 : : }
1051 : :
1052 : :
1053 : 0 : bool ScMatrixFormulaCellToken::operator==( const FormulaToken& r ) const
1054 : : {
1055 [ # # ]: 0 : const ScMatrixFormulaCellToken* p = dynamic_cast<const ScMatrixFormulaCellToken*>(&r);
1056 : 0 : return p && ScMatrixCellResultToken::operator==( r ) &&
1057 [ # # # # ]: 0 : nCols == p->nCols && nRows == p->nRows;
[ # # ][ # # ]
1058 : : }
1059 : 64 : void ScMatrixFormulaCellToken::Assign( const formula::FormulaToken& r )
1060 : : {
1061 [ - + ]: 64 : if (this == &r)
1062 : 64 : return;
1063 [ - + ]: 64 : const ScMatrixCellResultToken* p = dynamic_cast<const ScMatrixCellResultToken*>(&r);
1064 [ - + ]: 64 : if (p)
1065 : 0 : ScMatrixCellResultToken::Assign( *p);
1066 : : else
1067 : : {
1068 : : OSL_ENSURE( r.GetType() != svMatrix, "ScMatrixFormulaCellToken::operator=: assigning ScMatrixToken to ScMatrixFormulaCellToken is not proper, use ScMatrixCellResultToken instead");
1069 [ - + ]: 64 : if (r.GetType() == svMatrix)
1070 : : {
1071 : 0 : xUpperLeft = NULL;
1072 : 0 : xMatrix = static_cast<const ScToken&>(r).GetMatrix();
1073 : : }
1074 : : else
1075 : : {
1076 : 64 : xUpperLeft = &r;
1077 : 64 : xMatrix = NULL;
1078 : : }
1079 : : }
1080 : : }
1081 : 53 : void ScMatrixFormulaCellToken::SetUpperLeftDouble( double f )
1082 : : {
1083 [ - + - ]: 53 : switch (GetUpperLeftType())
1084 : : {
1085 : : case svDouble:
1086 : 0 : const_cast<FormulaToken*>(xUpperLeft.get())->GetDoubleAsReference() = f;
1087 : 0 : break;
1088 : : case svUnknown:
1089 [ + - ]: 53 : if (!xUpperLeft)
1090 : : {
1091 [ + - ]: 53 : xUpperLeft = new FormulaDoubleToken( f);
1092 : 53 : break;
1093 : : }
1094 : : // fall thru
1095 : : default:
1096 : : {
1097 : : OSL_FAIL("ScMatrixFormulaCellToken::SetUpperLeftDouble: not modifying unhandled token type");
1098 : : }
1099 : : }
1100 : 53 : }
1101 : :
1102 : :
1103 : 0 : double ScHybridCellToken::GetDouble() const { return fDouble; }
1104 : 126 : const String & ScHybridCellToken::GetString() const { return aString; }
1105 : 0 : bool ScHybridCellToken::operator==( const FormulaToken& r ) const
1106 : : {
1107 : 0 : return FormulaToken::operator==( r ) &&
1108 : 0 : fDouble == r.GetDouble() && aString == r.GetString() &&
1109 [ # # ][ # # : 0 : aFormula == static_cast<const ScHybridCellToken &>(r).GetFormula();
# # # # ]
1110 : : }
1111 : :
1112 : :
1113 : :
1114 : :
1115 : : //////////////////////////////////////////////////////////////////////////
1116 : :
1117 : 294 : bool ScTokenArray::AddFormulaToken(const com::sun::star::sheet::FormulaToken& _aToken,formula::ExternalReferenceHelper* _pRef)
1118 : : {
1119 : 294 : bool bError = FormulaTokenArray::AddFormulaToken(_aToken,_pRef);
1120 [ + + ]: 294 : if ( bError )
1121 : : {
1122 : 126 : bError = false;
1123 : 126 : const OpCode eOpCode = static_cast<OpCode>(_aToken.OpCode); //! assuming equal values for the moment
1124 : :
1125 : 126 : const uno::TypeClass eClass = _aToken.Data.getValueTypeClass();
1126 [ + + - ]: 126 : switch ( eClass )
1127 : : {
1128 : : case uno::TypeClass_STRUCT:
1129 : : {
1130 : 123 : uno::Type aType = _aToken.Data.getValueType();
1131 [ + + ]: 123 : if ( aType.equals( cppu::UnoType<sheet::SingleReference>::get() ) )
1132 : : {
1133 : : ScSingleRefData aSingleRef;
1134 : 48 : sheet::SingleReference aApiRef;
1135 [ + - ]: 48 : _aToken.Data >>= aApiRef;
1136 : 48 : lcl_SingleRefToCalc( aSingleRef, aApiRef );
1137 [ + - ]: 48 : if ( eOpCode == ocPush )
1138 [ + - ]: 48 : AddSingleReference( aSingleRef );
1139 [ # # ]: 0 : else if ( eOpCode == ocColRowName )
1140 [ # # ]: 0 : AddColRowName( aSingleRef );
1141 : : else
1142 : 48 : bError = true;
1143 : : }
1144 [ + + ]: 75 : else if ( aType.equals( cppu::UnoType<sheet::ComplexReference>::get() ) )
1145 : : {
1146 : : ScComplexRefData aComplRef;
1147 : 27 : sheet::ComplexReference aApiRef;
1148 [ + - ]: 27 : _aToken.Data >>= aApiRef;
1149 : 27 : lcl_SingleRefToCalc( aComplRef.Ref1, aApiRef.Reference1 );
1150 : 27 : lcl_SingleRefToCalc( aComplRef.Ref2, aApiRef.Reference2 );
1151 : :
1152 [ + - ]: 27 : if ( eOpCode == ocPush )
1153 [ + - ]: 27 : AddDoubleReference( aComplRef );
1154 : : else
1155 : 27 : bError = true;
1156 : : }
1157 [ + - ]: 48 : else if ( aType.equals( cppu::UnoType<sheet::NameToken>::get() ) )
1158 : : {
1159 : 48 : sheet::NameToken aTokenData;
1160 [ + - ]: 48 : _aToken.Data >>= aTokenData;
1161 [ + - ]: 48 : if ( eOpCode == ocName )
1162 [ + - ]: 48 : AddRangeName(aTokenData.Index, aTokenData.Global);
1163 [ # # ]: 0 : else if (eOpCode == ocDBArea)
1164 [ # # ]: 48 : AddDBRange(aTokenData.Index);
1165 : : }
1166 [ # # ]: 0 : else if ( aType.equals( cppu::UnoType<sheet::ExternalReference>::get() ) )
1167 : : {
1168 : 0 : sheet::ExternalReference aApiExtRef;
1169 [ # # ][ # # ]: 0 : if( (eOpCode == ocPush) && (_aToken.Data >>= aApiExtRef) && (0 <= aApiExtRef.Index) && (aApiExtRef.Index <= SAL_MAX_UINT16) )
[ # # ][ # # ]
[ # # ][ # # ]
1170 : : {
1171 : 0 : sal_uInt16 nFileId = static_cast< sal_uInt16 >( aApiExtRef.Index );
1172 : 0 : sheet::SingleReference aApiSRef;
1173 : 0 : sheet::ComplexReference aApiCRef;
1174 : 0 : ::rtl::OUString aName;
1175 [ # # ][ # # ]: 0 : if( aApiExtRef.Reference >>= aApiSRef )
1176 : : {
1177 : : // try to resolve cache index to sheet name
1178 : 0 : size_t nCacheId = static_cast< size_t >( aApiSRef.Sheet );
1179 [ # # ][ # # ]: 0 : String aTabName = _pRef->getCacheTableName( nFileId, nCacheId );
1180 [ # # ]: 0 : if( aTabName.Len() > 0 )
1181 : : {
1182 : : ScSingleRefData aSingleRef;
1183 : : // convert column/row settings, set sheet index to absolute
1184 : 0 : lcl_ExternalRefToCalc( aSingleRef, aApiSRef );
1185 [ # # ]: 0 : AddExternalSingleReference( nFileId, aTabName, aSingleRef );
1186 : : }
1187 : : else
1188 [ # # ]: 0 : bError = true;
1189 : : }
1190 [ # # ][ # # ]: 0 : else if( aApiExtRef.Reference >>= aApiCRef )
1191 : : {
1192 : : // try to resolve cache index to sheet name.
1193 : 0 : size_t nCacheId = static_cast< size_t >( aApiCRef.Reference1.Sheet );
1194 [ # # ][ # # ]: 0 : String aTabName = _pRef->getCacheTableName( nFileId, nCacheId );
1195 [ # # ]: 0 : if( aTabName.Len() > 0 )
1196 : : {
1197 : : ScComplexRefData aComplRef;
1198 : : // convert column/row settings, set sheet index to absolute
1199 : 0 : lcl_ExternalRefToCalc( aComplRef.Ref1, aApiCRef.Reference1 );
1200 : 0 : lcl_ExternalRefToCalc( aComplRef.Ref2, aApiCRef.Reference2 );
1201 : : // NOTE: This assumes that cached sheets are in consecutive order!
1202 : 0 : aComplRef.Ref2.nTab = aComplRef.Ref1.nTab + static_cast<SCsTAB>(aApiCRef.Reference2.Sheet - aApiCRef.Reference1.Sheet);
1203 [ # # ]: 0 : AddExternalDoubleReference( nFileId, aTabName, aComplRef );
1204 : : }
1205 : : else
1206 [ # # ]: 0 : bError = true;
1207 : : }
1208 [ # # ]: 0 : else if( aApiExtRef.Reference >>= aName )
1209 : : {
1210 [ # # ]: 0 : if( !aName.isEmpty() )
1211 [ # # ][ # # ]: 0 : AddExternalName( nFileId, aName );
[ # # ]
1212 : : else
1213 : 0 : bError = true;
1214 : : }
1215 : : else
1216 : 0 : bError = true;
1217 : : }
1218 : : else
1219 : 0 : bError = true;
1220 : : }
1221 : : else
1222 : 123 : bError = true; // unknown struct
1223 : : }
1224 : 123 : break;
1225 : : case uno::TypeClass_SEQUENCE:
1226 : : {
1227 [ - + ]: 3 : if ( eOpCode != ocPush )
1228 : 0 : bError = true; // not an inline array
1229 [ - + ]: 6 : else if (!_aToken.Data.getValueType().equals( getCppuType(
1230 : 6 : (uno::Sequence< uno::Sequence< uno::Any > > *)0)))
1231 : 0 : bError = true; // unexpected sequence type
1232 : : else
1233 : : {
1234 [ + - ]: 3 : ScMatrixRef xMat = ScSequenceToMatrix::CreateMixedMatrix( _aToken.Data);
1235 [ + - ]: 3 : if (xMat)
1236 [ + - ]: 3 : AddMatrix( xMat);
1237 : : else
1238 [ + - ]: 3 : bError = true;
1239 : : }
1240 : : }
1241 : 3 : break;
1242 : : default:
1243 : 126 : bError = true;
1244 : : }
1245 : : }
1246 : 294 : return bError;
1247 : : }
1248 : 547 : bool ScTokenArray::ImplGetReference( ScRange& rRange, bool bValidOnly ) const
1249 : : {
1250 : 547 : bool bIs = false;
1251 [ + - ][ + - ]: 547 : if ( pCode && nLen == 1 )
1252 : : {
1253 : 547 : const FormulaToken* pToken = pCode[0];
1254 [ + - ]: 547 : if ( pToken )
1255 : : {
1256 [ + + ]: 547 : if ( pToken->GetType() == svSingleRef )
1257 : : {
1258 : 447 : const ScSingleRefData& rRef = ((const ScSingleRefToken*)pToken)->GetSingleRef();
1259 : 447 : rRange.aStart = rRange.aEnd = ScAddress( rRef.nCol, rRef.nRow, rRef.nTab );
1260 [ + - ][ + + ]: 447 : bIs = !bValidOnly || !rRef.IsDeleted();
1261 : : }
1262 [ + + ]: 100 : else if ( pToken->GetType() == svDoubleRef )
1263 : : {
1264 : 98 : const ScComplexRefData& rCompl = ((const ScDoubleRefToken*)pToken)->GetDoubleRef();
1265 : 98 : const ScSingleRefData& rRef1 = rCompl.Ref1;
1266 : 98 : const ScSingleRefData& rRef2 = rCompl.Ref2;
1267 : 98 : rRange.aStart = ScAddress( rRef1.nCol, rRef1.nRow, rRef1.nTab );
1268 : 98 : rRange.aEnd = ScAddress( rRef2.nCol, rRef2.nRow, rRef2.nTab );
1269 [ + - ][ + - ]: 98 : bIs = !bValidOnly || (!rRef1.IsDeleted() && !rRef2.IsDeleted());
[ + + ]
1270 : : }
1271 : : }
1272 : : }
1273 : 547 : return bIs;
1274 : : }
1275 : :
1276 : 143 : bool ScTokenArray::IsReference( ScRange& rRange ) const
1277 : : {
1278 : 143 : return ImplGetReference( rRange, false );
1279 : : }
1280 : :
1281 : 404 : bool ScTokenArray::IsValidReference( ScRange& rRange ) const
1282 : : {
1283 : 404 : return ImplGetReference( rRange, true );
1284 : : }
1285 : :
1286 : : ////////////////////////////////////////////////////////////////////////////
1287 : :
1288 : 7440 : ScTokenArray::ScTokenArray()
1289 : : {
1290 : 7440 : }
1291 : :
1292 : 7536 : ScTokenArray::ScTokenArray( const ScTokenArray& rArr ) : FormulaTokenArray(rArr)
1293 : : {
1294 : 7536 : }
1295 : :
1296 : 14386 : ScTokenArray::~ScTokenArray()
1297 : : {
1298 [ - + ]: 24327 : }
1299 : :
1300 : :
1301 : :
1302 : 0 : ScTokenArray& ScTokenArray::operator=( const ScTokenArray& rArr )
1303 : : {
1304 : 0 : Clear();
1305 : 0 : Assign( rArr );
1306 : 0 : return *this;
1307 : : }
1308 : :
1309 : 1529 : ScTokenArray* ScTokenArray::Clone() const
1310 : : {
1311 [ + - ]: 1529 : ScTokenArray* p = new ScTokenArray();
1312 : 1529 : p->nLen = nLen;
1313 : 1529 : p->nRPN = nRPN;
1314 : 1529 : p->nRefs = nRefs;
1315 : 1529 : p->nMode = nMode;
1316 : 1529 : p->nError = nError;
1317 : 1529 : p->bHyperLink = bHyperLink;
1318 : : FormulaToken** pp;
1319 [ + + ]: 1529 : if( nLen )
1320 : : {
1321 : 1485 : pp = p->pCode = new FormulaToken*[ nLen ];
1322 : 1485 : memcpy( pp, pCode, nLen * sizeof( ScToken* ) );
1323 [ + + ]: 4255 : for( sal_uInt16 i = 0; i < nLen; i++, pp++ )
1324 : : {
1325 : 2770 : *pp = (*pp)->Clone();
1326 : 2770 : (*pp)->IncRef();
1327 : : }
1328 : : }
1329 [ + + ]: 1529 : if( nRPN )
1330 : : {
1331 : 338 : pp = p->pRPN = new FormulaToken*[ nRPN ];
1332 : 338 : memcpy( pp, pRPN, nRPN * sizeof( ScToken* ) );
1333 [ + + ]: 1245 : for( sal_uInt16 i = 0; i < nRPN; i++, pp++ )
1334 : : {
1335 : 907 : FormulaToken* t = *pp;
1336 [ + + ]: 907 : if( t->GetRef() > 1 )
1337 : : {
1338 : 867 : FormulaToken** p2 = pCode;
1339 : 867 : sal_uInt16 nIdx = 0xFFFF;
1340 [ + - ]: 3042 : for( sal_uInt16 j = 0; j < nLen; j++, p2++ )
1341 : : {
1342 [ + + ]: 3042 : if( *p2 == t )
1343 : : {
1344 : 867 : nIdx = j; break;
1345 : : }
1346 : : }
1347 [ - + ]: 867 : if( nIdx == 0xFFFF )
1348 : 0 : *pp = t->Clone();
1349 : : else
1350 : 867 : *pp = p->pCode[ nIdx ];
1351 : : }
1352 : : else
1353 : 40 : *pp = t->Clone();
1354 : 907 : (*pp)->IncRef();
1355 : : }
1356 : : }
1357 : 1529 : return p;
1358 : : }
1359 : :
1360 : 39909 : FormulaToken* ScTokenArray::AddRawToken( const ScRawToken& r )
1361 : : {
1362 : 39909 : return Add( r.CreateToken() );
1363 : : }
1364 : :
1365 : : // Utility function to ensure that there is strict alternation of values and
1366 : : // seperators.
1367 : : static bool
1368 : 129 : checkArraySep( bool & bPrevWasSep, bool bNewVal )
1369 : : {
1370 : 129 : bool bResult = (bPrevWasSep == bNewVal);
1371 : 129 : bPrevWasSep = bNewVal;
1372 : 129 : return bResult;
1373 : : }
1374 : :
1375 : 15 : FormulaToken* ScTokenArray::MergeArray( )
1376 : : {
1377 : 15 : int nCol = -1, nRow = 0;
1378 : 15 : int i, nPrevRowSep = -1, nStart = 0;
1379 : 15 : bool bPrevWasSep = false; // top of stack is ocArrayClose
1380 : : FormulaToken* t;
1381 : 15 : bool bNumeric = false; // numeric value encountered in current element
1382 : :
1383 : : // (1) Iterate from the end to the start to find matrix dims
1384 : : // and do basic validation.
1385 [ + + ]: 144 : for ( i = nLen ; i-- > nStart ; )
1386 : : {
1387 : 129 : t = pCode[i];
1388 [ + - + + : 129 : switch ( t->GetOpCode() )
+ + - -
- ]
1389 : : {
1390 : : case ocPush :
1391 [ - + ]: 57 : if( checkArraySep( bPrevWasSep, false ) )
1392 : : {
1393 : 0 : return NULL;
1394 : : }
1395 : :
1396 : : // no references or nested arrays
1397 [ - + ][ # # ]: 57 : if ( t->GetType() != svDouble && t->GetType() != svString )
[ - + ]
1398 : : {
1399 : 0 : return NULL;
1400 : : }
1401 : 57 : bNumeric = (t->GetType() == svDouble);
1402 : 57 : break;
1403 : :
1404 : : case ocMissing :
1405 : : case ocTrue :
1406 : : case ocFalse :
1407 [ # # ]: 0 : if( checkArraySep( bPrevWasSep, false ) )
1408 : : {
1409 : 0 : return NULL;
1410 : : }
1411 : 0 : bNumeric = false;
1412 : 0 : break;
1413 : :
1414 : : case ocArrayColSep :
1415 : : case ocSep :
1416 [ - + ]: 36 : if( checkArraySep( bPrevWasSep, true ) )
1417 : : {
1418 : 0 : return NULL;
1419 : : }
1420 : 36 : bNumeric = false;
1421 : 36 : break;
1422 : :
1423 : : case ocArrayClose :
1424 : : // not possible with the , but check just in case
1425 : : // something changes in the future
1426 [ - + ]: 15 : if( i != (nLen-1))
1427 : : {
1428 : 0 : return NULL;
1429 : : }
1430 : :
1431 [ - + ]: 15 : if( checkArraySep( bPrevWasSep, true ) )
1432 : : {
1433 : 0 : return NULL;
1434 : : }
1435 : :
1436 : 15 : nPrevRowSep = i;
1437 : 15 : bNumeric = false;
1438 : 15 : break;
1439 : :
1440 : : case ocArrayOpen :
1441 : 15 : nStart = i; // stop iteration
1442 : : // fall through to ArrayRowSep
1443 : :
1444 : : case ocArrayRowSep :
1445 [ - + ]: 21 : if( checkArraySep( bPrevWasSep, true ) )
1446 : : {
1447 : 0 : return NULL;
1448 : : }
1449 : :
1450 [ + - ][ - + ]: 21 : if( nPrevRowSep < 0 || // missing ocArrayClose
1451 : : ((nPrevRowSep - i) % 2) == 1) // no complex elements
1452 : : {
1453 : 0 : return NULL;
1454 : : }
1455 : :
1456 [ + + ]: 21 : if( nCol < 0 )
1457 : : {
1458 : 15 : nCol = (nPrevRowSep - i) / 2;
1459 : : }
1460 [ - + ]: 6 : else if( (nPrevRowSep - i)/2 != nCol) // irregular array
1461 : : {
1462 : 0 : return NULL;
1463 : : }
1464 : :
1465 : 21 : nPrevRowSep = i;
1466 : 21 : nRow++;
1467 : 21 : bNumeric = false;
1468 : 21 : break;
1469 : :
1470 : : case ocNegSub :
1471 : : case ocAdd :
1472 : : // negation or unary plus must precede numeric value
1473 [ # # ]: 0 : if( !bNumeric )
1474 : : {
1475 : 0 : return NULL;
1476 : : }
1477 : 0 : --nPrevRowSep; // shorten this row by 1
1478 : 0 : bNumeric = false; // one level only, no --42
1479 : 0 : break;
1480 : :
1481 : : case ocSpaces :
1482 : : // ignore spaces
1483 : 0 : --nPrevRowSep; // shorten this row by 1
1484 : 0 : break;
1485 : :
1486 : : default :
1487 : : // no functions or operators
1488 : 0 : return NULL;
1489 : : }
1490 : : }
1491 [ + - ][ - + ]: 15 : if( nCol <= 0 || nRow <= 0 )
1492 : 0 : return NULL;
1493 : :
1494 : 15 : int nSign = 1;
1495 [ + - ][ + - ]: 15 : ScMatrix* pArray = new ScMatrix(nCol, nRow, 0.0);
1496 [ + + ]: 144 : for ( i = nStart, nCol = 0, nRow = 0 ; i < nLen ; i++ )
1497 : : {
1498 : 129 : t = pCode[i];
1499 : :
1500 [ + - - - : 129 : switch ( t->GetOpCode() )
+ + - + ]
1501 : : {
1502 : : case ocPush :
1503 [ + - ]: 57 : if ( t->GetType() == svDouble )
1504 : : {
1505 [ + - ][ + - ]: 57 : pArray->PutDouble( t->GetDouble() * nSign, nCol, nRow );
1506 : 57 : nSign = 1;
1507 : : }
1508 [ # # ]: 0 : else if ( t->GetType() == svString )
1509 : : {
1510 [ # # ][ # # ]: 0 : pArray->PutString( t->GetString(), nCol, nRow );
[ # # ]
1511 : : }
1512 : 57 : break;
1513 : :
1514 : : case ocMissing :
1515 [ # # ]: 0 : pArray->PutEmpty( nCol, nRow );
1516 : 0 : break;
1517 : :
1518 : : case ocTrue :
1519 [ # # ]: 0 : pArray->PutBoolean( true, nCol, nRow );
1520 : 0 : break;
1521 : :
1522 : : case ocFalse :
1523 [ # # ]: 0 : pArray->PutBoolean( false, nCol, nRow );
1524 : 0 : break;
1525 : :
1526 : : case ocArrayColSep :
1527 : : case ocSep :
1528 : 36 : nCol++;
1529 : 36 : break;
1530 : :
1531 : : case ocArrayRowSep :
1532 : 6 : nRow++; nCol = 0;
1533 : 6 : break;
1534 : :
1535 : : case ocNegSub :
1536 : 0 : nSign = -nSign;
1537 : 0 : break;
1538 : :
1539 : : default :
1540 : 30 : break;
1541 : : }
1542 : 129 : pCode[i] = NULL;
1543 [ + - ]: 129 : t->DecRef();
1544 : : }
1545 : 15 : nLen = sal_uInt16( nStart );
1546 [ + - ][ + - ]: 15 : return AddMatrix( pArray );
1547 : : }
1548 : :
1549 : :
1550 : 0 : FormulaToken* ScTokenArray::MergeRangeReference( const ScAddress & rPos )
1551 : : {
1552 [ # # ][ # # ]: 0 : if (!pCode || !nLen)
1553 : 0 : return NULL;
1554 : 0 : sal_uInt16 nIdx = nLen;
1555 : : FormulaToken *p1, *p2, *p3; // ref, ocRange, ref
1556 : : // The actual types are checked in ExtendRangeReference().
1557 [ # # ][ # # ]: 0 : if (((p3 = PeekPrev(nIdx)) != 0) &&
[ # # ]
[ # # # # ]
[ # # ][ # # ]
[ # # ]
1558 : 0 : (((p2 = PeekPrev(nIdx)) != 0) && p2->GetOpCode() == ocRange) &&
1559 : 0 : ((p1 = PeekPrev(nIdx)) != 0))
1560 : : {
1561 [ # # ]: 0 : FormulaTokenRef p = ScToken::ExtendRangeReference( *p1, *p3, rPos, true);
1562 [ # # ]: 0 : if (p)
1563 : : {
1564 : 0 : p->IncRef();
1565 [ # # ]: 0 : p1->DecRef();
1566 [ # # ]: 0 : p2->DecRef();
1567 [ # # ]: 0 : p3->DecRef();
1568 : 0 : nLen -= 2;
1569 : 0 : pCode[ nLen-1 ] = p.get();
1570 : 0 : nRefs--;
1571 [ # # ]: 0 : }
1572 : : }
1573 : 0 : return pCode[ nLen-1 ];
1574 : : }
1575 : :
1576 : 39829 : FormulaToken* ScTokenArray::AddOpCode( OpCode e )
1577 : : {
1578 : 39829 : ScRawToken t;
1579 : 39829 : t.SetOpCode( e );
1580 [ + - ]: 39829 : return AddRawToken( t );
1581 : : }
1582 : :
1583 : 3597 : FormulaToken* ScTokenArray::AddSingleReference( const ScSingleRefData& rRef )
1584 : : {
1585 [ + - ]: 3597 : return Add( new ScSingleRefToken( rRef ) );
1586 : : }
1587 : :
1588 : 84 : FormulaToken* ScTokenArray::AddMatrixSingleReference( const ScSingleRefData& rRef )
1589 : : {
1590 [ + - ]: 84 : return Add( new ScSingleRefToken( rRef, ocMatRef ) );
1591 : : }
1592 : :
1593 : 5201 : FormulaToken* ScTokenArray::AddDoubleReference( const ScComplexRefData& rRef )
1594 : : {
1595 [ + - ]: 5201 : return Add( new ScDoubleRefToken( rRef ) );
1596 : : }
1597 : :
1598 : 21 : FormulaToken* ScTokenArray::AddMatrix( const ScMatrixRef& p )
1599 : : {
1600 [ + - ][ + - ]: 21 : return Add( new ScMatrixToken( p ) );
[ + - ]
1601 : : }
1602 : :
1603 : 90 : FormulaToken* ScTokenArray::AddRangeName( sal_uInt16 n, bool bGlobal )
1604 : : {
1605 [ + - ]: 90 : return Add( new FormulaIndexToken( ocName, n, bGlobal));
1606 : : }
1607 : :
1608 : 0 : FormulaToken* ScTokenArray::AddDBRange( sal_uInt16 n )
1609 : : {
1610 [ # # ]: 0 : return Add( new FormulaIndexToken( ocDBArea, n));
1611 : : }
1612 : :
1613 : 0 : FormulaToken* ScTokenArray::AddExternalName( sal_uInt16 nFileId, const String& rName )
1614 : : {
1615 [ # # ]: 0 : return Add( new ScExternalNameToken(nFileId, rName) );
1616 : : }
1617 : :
1618 : 0 : FormulaToken* ScTokenArray::AddExternalSingleReference( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef )
1619 : : {
1620 [ # # ]: 0 : return Add( new ScExternalSingleRefToken(nFileId, rTabName, rRef) );
1621 : : }
1622 : :
1623 : 0 : FormulaToken* ScTokenArray::AddExternalDoubleReference( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef )
1624 : : {
1625 [ # # ]: 0 : return Add( new ScExternalDoubleRefToken(nFileId, rTabName, rRef) );
1626 : : }
1627 : :
1628 : 0 : FormulaToken* ScTokenArray::AddColRowName( const ScSingleRefData& rRef )
1629 : : {
1630 [ # # ]: 0 : return Add( new ScSingleRefToken( rRef, ocColRowName ) );
1631 : : }
1632 : :
1633 : 0 : bool ScTokenArray::GetAdjacentExtendOfOuterFuncRefs( SCCOLROW& nExtend,
1634 : : const ScAddress& rPos, ScDirection eDir )
1635 : : {
1636 : 0 : SCCOL nCol = 0;
1637 : 0 : SCROW nRow = 0;
1638 [ # # # # : 0 : switch ( eDir )
# ]
1639 : : {
1640 : : case DIR_BOTTOM :
1641 [ # # ]: 0 : if ( rPos.Row() < MAXROW )
1642 : 0 : nRow = (nExtend = rPos.Row()) + 1;
1643 : : else
1644 : 0 : return false;
1645 : 0 : break;
1646 : : case DIR_RIGHT :
1647 [ # # ]: 0 : if ( rPos.Col() < MAXCOL )
1648 : 0 : nCol = static_cast<SCCOL>(nExtend = rPos.Col()) + 1;
1649 : : else
1650 : 0 : return false;
1651 : 0 : break;
1652 : : case DIR_TOP :
1653 [ # # ]: 0 : if ( rPos.Row() > 0 )
1654 : 0 : nRow = (nExtend = rPos.Row()) - 1;
1655 : : else
1656 : 0 : return false;
1657 : 0 : break;
1658 : : case DIR_LEFT :
1659 [ # # ]: 0 : if ( rPos.Col() > 0 )
1660 : 0 : nCol = static_cast<SCCOL>(nExtend = rPos.Col()) - 1;
1661 : : else
1662 : 0 : return false;
1663 : 0 : break;
1664 : : default:
1665 : : OSL_FAIL( "unknown Direction" );
1666 : 0 : return false;
1667 : : }
1668 [ # # ][ # # ]: 0 : if ( pRPN && nRPN )
1669 : : {
1670 : 0 : FormulaToken* t = pRPN[nRPN-1];
1671 [ # # ]: 0 : if ( t->GetType() == svByte )
1672 : : {
1673 : 0 : sal_uInt8 nParamCount = t->GetByte();
1674 [ # # ][ # # ]: 0 : if ( nParamCount && nRPN > nParamCount )
1675 : : {
1676 : 0 : bool bRet = false;
1677 : 0 : sal_uInt16 nParam = nRPN - nParamCount - 1;
1678 [ # # ]: 0 : for ( ; nParam < nRPN-1; nParam++ )
1679 : : {
1680 : 0 : FormulaToken* p = pRPN[nParam];
1681 [ # # # ]: 0 : switch ( p->GetType() )
1682 : : {
1683 : : case svSingleRef :
1684 : : {
1685 : 0 : ScSingleRefData& rRef = static_cast<ScToken*>(p)->GetSingleRef();
1686 : 0 : rRef.CalcAbsIfRel( rPos );
1687 [ # # # # : 0 : switch ( eDir )
# ]
1688 : : {
1689 : : case DIR_BOTTOM :
1690 [ # # ][ # # ]: 0 : if ( rRef.nRow == nRow
1691 : : && rRef.nRow > nExtend )
1692 : : {
1693 : 0 : nExtend = rRef.nRow;
1694 : 0 : bRet = true;
1695 : : }
1696 : 0 : break;
1697 : : case DIR_RIGHT :
1698 [ # # ][ # # ]: 0 : if ( rRef.nCol == nCol
1699 : : && static_cast<SCCOLROW>(rRef.nCol)
1700 : : > nExtend )
1701 : : {
1702 : 0 : nExtend = rRef.nCol;
1703 : 0 : bRet = true;
1704 : : }
1705 : 0 : break;
1706 : : case DIR_TOP :
1707 [ # # ][ # # ]: 0 : if ( rRef.nRow == nRow
1708 : : && rRef.nRow < nExtend )
1709 : : {
1710 : 0 : nExtend = rRef.nRow;
1711 : 0 : bRet = true;
1712 : : }
1713 : 0 : break;
1714 : : case DIR_LEFT :
1715 [ # # ][ # # ]: 0 : if ( rRef.nCol == nCol
1716 : : && static_cast<SCCOLROW>(rRef.nCol)
1717 : : < nExtend )
1718 : : {
1719 : 0 : nExtend = rRef.nCol;
1720 : 0 : bRet = true;
1721 : : }
1722 : 0 : break;
1723 : : }
1724 : : }
1725 : 0 : break;
1726 : : case svDoubleRef :
1727 : : {
1728 : 0 : ScComplexRefData& rRef = static_cast<ScToken*>(p)->GetDoubleRef();
1729 : 0 : rRef.CalcAbsIfRel( rPos );
1730 [ # # # # : 0 : switch ( eDir )
# ]
1731 : : {
1732 : : case DIR_BOTTOM :
1733 [ # # ][ # # ]: 0 : if ( rRef.Ref1.nRow == nRow
1734 : : && rRef.Ref2.nRow > nExtend )
1735 : : {
1736 : 0 : nExtend = rRef.Ref2.nRow;
1737 : 0 : bRet = true;
1738 : : }
1739 : 0 : break;
1740 : : case DIR_RIGHT :
1741 [ # # ][ # # ]: 0 : if ( rRef.Ref1.nCol == nCol &&
1742 : : static_cast<SCCOLROW>(rRef.Ref2.nCol)
1743 : : > nExtend )
1744 : : {
1745 : 0 : nExtend = rRef.Ref2.nCol;
1746 : 0 : bRet = true;
1747 : : }
1748 : 0 : break;
1749 : : case DIR_TOP :
1750 [ # # ][ # # ]: 0 : if ( rRef.Ref2.nRow == nRow
1751 : : && rRef.Ref1.nRow < nExtend )
1752 : : {
1753 : 0 : nExtend = rRef.Ref1.nRow;
1754 : 0 : bRet = true;
1755 : : }
1756 : 0 : break;
1757 : : case DIR_LEFT :
1758 [ # # ][ # # ]: 0 : if ( rRef.Ref2.nCol == nCol &&
1759 : : static_cast<SCCOLROW>(rRef.Ref1.nCol)
1760 : : < nExtend )
1761 : : {
1762 : 0 : nExtend = rRef.Ref1.nCol;
1763 : 0 : bRet = true;
1764 : : }
1765 : 0 : break;
1766 : : }
1767 : : }
1768 : 0 : break;
1769 : : default:
1770 : : {
1771 : : // added to avoid warnings
1772 : : }
1773 : : } // switch
1774 : : } // for
1775 : 0 : return bRet;
1776 : : }
1777 : : }
1778 : : }
1779 : 0 : return false;
1780 : : }
1781 : :
1782 : :
1783 : 0 : void ScTokenArray::ReadjustRelative3DReferences( const ScAddress& rOldPos,
1784 : : const ScAddress& rNewPos )
1785 : : {
1786 [ # # ]: 0 : for ( sal_uInt16 j=0; j<nLen; ++j )
1787 : : {
1788 [ # # # ]: 0 : switch ( pCode[j]->GetType() )
1789 : : {
1790 : : case svDoubleRef :
1791 : : {
1792 : 0 : ScSingleRefData& rRef2 = static_cast<ScToken*>(pCode[j])->GetSingleRef2();
1793 : : // Also adjust if the reference is of the form Sheet1.A2:A3
1794 [ # # ][ # # ]: 0 : if ( rRef2.IsFlag3D() || static_cast<ScToken*>(pCode[j])->GetSingleRef().IsFlag3D() )
[ # # ]
1795 : : {
1796 : 0 : rRef2.CalcAbsIfRel( rOldPos );
1797 : 0 : rRef2.CalcRelFromAbs( rNewPos );
1798 : : }
1799 : : }
1800 : : //! fallthru
1801 : : case svSingleRef :
1802 : : {
1803 : 0 : ScSingleRefData& rRef1 = static_cast<ScToken*>(pCode[j])->GetSingleRef();
1804 [ # # ]: 0 : if ( rRef1.IsFlag3D() )
1805 : : {
1806 : 0 : rRef1.CalcAbsIfRel( rOldPos );
1807 : 0 : rRef1.CalcRelFromAbs( rNewPos );
1808 : : }
1809 : : }
1810 : 0 : break;
1811 : : default:
1812 : : {
1813 : : // added to avoid warnings
1814 : : }
1815 : : }
1816 : : }
1817 : 0 : }
1818 : :
1819 : : namespace {
1820 : :
1821 : 11 : void GetExternalTableData(const ScDocument* pOldDoc, const ScDocument* pNewDoc, const SCTAB nTab, rtl::OUString& rTabName, sal_uInt16& rFileId)
1822 : : {
1823 : 11 : rtl::OUString aFileName = pOldDoc->GetFileURL();;
1824 [ + - ][ + - ]: 11 : rFileId = pNewDoc->GetExternalRefManager()->getExternalFileId(aFileName);
1825 [ + - ]: 11 : rTabName = pOldDoc->GetCopyTabName(nTab);
1826 [ + + ]: 11 : if (rTabName.isEmpty())
1827 [ + - ]: 11 : pOldDoc->GetName(nTab, rTabName);
1828 : 11 : }
1829 : :
1830 : 47 : bool IsInCopyRange( const ScRange& rRange, const ScDocument* pClipDoc )
1831 : : {
1832 : 47 : ScClipParam& rClipParam = const_cast<ScDocument*>(pClipDoc)->GetClipParam();
1833 : 47 : return rClipParam.maRanges.In(rRange);
1834 : : }
1835 : :
1836 : 493 : bool SkipReference(ScToken* pToken, const ScAddress& rPos, const ScDocument* pOldDoc, bool bRangeName, bool bCheckCopyArea)
1837 : : {
1838 : 493 : ScRange aRange;
1839 : :
1840 [ + - ]: 493 : pToken->CalcAbsIfRel(rPos);
1841 [ + - ][ + - ]: 493 : if (!ScRefTokenHelper::getRangeFromToken(aRange, pToken))
[ - + ]
1842 : 0 : return true;
1843 : :
1844 [ + + ][ + - ]: 493 : if (bRangeName && aRange.aStart.Tab() == rPos.Tab())
[ + + ]
1845 : : {
1846 [ - + - ]: 4 : switch (pToken->GetType())
1847 : : {
1848 : : case svDoubleRef:
1849 : : {
1850 [ # # ]: 0 : ScSingleRefData& rRef = pToken->GetSingleRef2();
1851 [ # # ][ # # ]: 0 : if (rRef.IsColRel() || rRef.IsRowRel())
[ # # ]
1852 : 0 : return true;
1853 : : } // fall through
1854 : : case svSingleRef:
1855 : : {
1856 [ + - ]: 4 : ScSingleRefData& rRef = pToken->GetSingleRef();
1857 [ + - ][ - + ]: 4 : if (rRef.IsColRel() || rRef.IsRowRel())
[ - + ]
1858 : 0 : return true;
1859 : : }
1860 : 4 : break;
1861 : : default:
1862 : 4 : break;
1863 : : }
1864 : : }
1865 : :
1866 [ + + ][ + - ]: 493 : if (bCheckCopyArea && IsInCopyRange(aRange, pOldDoc))
[ + + ][ + + ]
1867 : 30 : return true;
1868 : :
1869 : 493 : return false;
1870 : : }
1871 : :
1872 : 15 : void AdjustSingleRefData( ScSingleRefData& rRef, const ScAddress& rOldPos, const ScAddress& rNewPos)
1873 : : {
1874 : 15 : SCsCOL nCols = rNewPos.Col() - rOldPos.Col();
1875 : 15 : SCsROW nRows = rNewPos.Row() - rOldPos.Row();
1876 : 15 : SCsTAB nTabs = rNewPos.Tab() - rOldPos.Tab();
1877 : :
1878 [ + + ]: 15 : if (!rRef.IsColRel())
1879 : 11 : rRef.nCol += nCols;
1880 : :
1881 [ + + ]: 15 : if (!rRef.IsRowRel())
1882 : 11 : rRef.nRow += nRows;
1883 : :
1884 [ + + ]: 15 : if (!rRef.IsTabRel())
1885 : 5 : rRef.nTab += nTabs;
1886 : 15 : }
1887 : :
1888 : : }
1889 : :
1890 : 32 : void ScTokenArray::ReadjustAbsolute3DReferences( const ScDocument* pOldDoc, const ScDocument* pNewDoc, const ScAddress& rPos, bool bRangeName )
1891 : : {
1892 [ + + ]: 83 : for ( sal_uInt16 j=0; j<nLen; ++j )
1893 : : {
1894 [ - + + ]: 51 : switch ( pCode[j]->GetType() )
1895 : : {
1896 : : case svDoubleRef :
1897 : : {
1898 [ # # ]: 0 : if (SkipReference(static_cast<ScToken*>(pCode[j]), rPos, pOldDoc, bRangeName, true))
1899 : 0 : continue;
1900 : :
1901 : 0 : ScComplexRefData& rRef = static_cast<ScToken*>(pCode[j])->GetDoubleRef();
1902 : 0 : ScSingleRefData& rRef2 = rRef.Ref2;
1903 : 0 : ScSingleRefData& rRef1 = rRef.Ref1;
1904 : :
1905 [ # # ][ # # ]: 0 : if ( (rRef2.IsFlag3D() && !rRef2.IsTabRel()) || (rRef1.IsFlag3D() && !rRef1.IsTabRel()) )
[ # # ][ # # ]
[ # # ]
1906 : : {
1907 : 0 : rtl::OUString aTabName;
1908 : : sal_uInt16 nFileId;
1909 [ # # ]: 0 : GetExternalTableData(pOldDoc, pNewDoc, rRef1.nTab, aTabName, nFileId);
1910 [ # # ]: 0 : pCode[j]->DecRef();
1911 [ # # ][ # # ]: 0 : ScExternalDoubleRefToken* pToken = new ScExternalDoubleRefToken(nFileId, aTabName, rRef);
[ # # ][ # # ]
1912 : 0 : pToken->IncRef();
1913 : 0 : pCode[j] = pToken;
1914 : : }
1915 : : }
1916 : 0 : break;
1917 : : case svSingleRef :
1918 : : {
1919 [ + + ]: 29 : if (SkipReference(static_cast<ScToken*>(pCode[j]), rPos, pOldDoc, bRangeName, true))
1920 : 15 : continue;
1921 : :
1922 : 14 : ScSingleRefData& rRef = static_cast<ScToken*>(pCode[j])->GetSingleRef();
1923 : :
1924 [ + - ][ + + ]: 14 : if ( rRef.IsFlag3D() && !rRef.IsTabRel() )
[ + + ]
1925 : : {
1926 : 11 : rtl::OUString aTabName;
1927 : : sal_uInt16 nFileId;
1928 [ + - ]: 11 : GetExternalTableData(pOldDoc, pNewDoc, rRef.nTab, aTabName, nFileId);
1929 : : //replace with ScExternalSingleRefToken and adjust references
1930 [ + - ]: 11 : pCode[j]->DecRef();
1931 [ + - ][ + - ]: 11 : ScExternalSingleRefToken* pToken = new ScExternalSingleRefToken(nFileId, aTabName, rRef);
[ + - ][ + - ]
1932 : 11 : pToken->IncRef();
1933 : 11 : pCode[j] = pToken;
1934 : : }
1935 : : }
1936 : 14 : break;
1937 : : default:
1938 : : {
1939 : : // added to avoid warnings
1940 : : }
1941 : : }
1942 : : }
1943 : 32 : }
1944 : :
1945 : 302 : void ScTokenArray::AdjustAbsoluteRefs( const ScDocument* pOldDoc, const ScAddress& rOldPos, const ScAddress& rNewPos, bool bRangeName, bool bCheckCopyRange)
1946 : : {
1947 [ + + ]: 1752 : for ( sal_uInt16 j=0; j<nLen; ++j )
1948 : : {
1949 [ + + + ]: 1450 : switch ( pCode[j]->GetType() )
1950 : : {
1951 : : case svDoubleRef :
1952 : : {
1953 [ + - ]: 73 : if (!SkipReference(static_cast<ScToken*>(pCode[j]), rOldPos, pOldDoc, false, bCheckCopyRange))
1954 : 73 : continue;
1955 : :
1956 : 0 : ScComplexRefData& rRef = static_cast<ScToken*>(pCode[j])->GetDoubleRef();
1957 : 0 : ScSingleRefData& rRef2 = rRef.Ref2;
1958 : 0 : ScSingleRefData& rRef1 = rRef.Ref1;
1959 : :
1960 : : // for range names only adjust if all parts are absolute
1961 [ # # ][ # # ]: 0 : if (!bRangeName || !(rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel()))
[ # # ][ # # ]
[ # # ]
1962 : 0 : AdjustSingleRefData( rRef1, rOldPos, rNewPos );
1963 [ # # ][ # # ]: 0 : if (!bRangeName || !(rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel()))
[ # # ][ # # ]
[ # # ]
1964 : 0 : AdjustSingleRefData( rRef2, rOldPos, rNewPos );
1965 : :
1966 : : }
1967 : 0 : break;
1968 : : case svSingleRef :
1969 : : {
1970 [ + + ]: 391 : if (!SkipReference(static_cast<ScToken*>(pCode[j]), rOldPos, pOldDoc, false, bCheckCopyRange))
1971 : 376 : continue;
1972 : :
1973 : 15 : ScSingleRefData& rRef = static_cast<ScToken*>(pCode[j])->GetSingleRef();
1974 : :
1975 : : // for range names only adjust if all parts are absolute
1976 [ # # ][ # # ]: 15 : if (!bRangeName || !(rRef.IsColRel() || rRef.IsRowRel() || rRef.IsTabRel()))
[ # # ][ + - ]
[ - + ]
1977 : 15 : AdjustSingleRefData( rRef, rOldPos, rNewPos );
1978 : :
1979 : :
1980 : : }
1981 : 15 : break;
1982 : : default:
1983 : : {
1984 : : // added to avoid warnings
1985 : : }
1986 : : }
1987 : : }
1988 [ + - ][ + - ]: 455 : }
1989 : :
1990 : :
1991 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|