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 : : #ifndef SC_TOKEN_HXX
30 : : #define SC_TOKEN_HXX
31 : :
32 : : #include <memory>
33 : : #include <vector>
34 : : #include <boost/intrusive_ptr.hpp>
35 : :
36 : : #include "formula/opcode.hxx"
37 : : #include "refdata.hxx"
38 : : #include "scmatrix.hxx"
39 : : #include <tools/mempool.hxx>
40 : : #include "scdllapi.h"
41 : : #include "formula/IFunctionDescription.hxx"
42 : : #include "formula/token.hxx"
43 : :
44 : :
45 : : class ScJumpMatrix;
46 : : class ScToken;
47 : :
48 : : typedef ::std::vector< ScComplexRefData > ScRefList;
49 : : typedef ::boost::intrusive_ptr<ScToken> ScTokenRef;
50 : :
51 : : class SC_DLLPUBLIC ScToken : public formula::FormulaToken
52 : : {
53 : : private:
54 : : // not implemented, prevent usage
55 : : ScToken();
56 : : ScToken& operator=( const ScToken& );
57 : :
58 : : protected:
59 : :
60 : 29891 : ScToken( formula::StackVar eTypeP,OpCode e = ocPush ) : formula::FormulaToken(eTypeP,e) {}
61 : 13640 : ScToken( const ScToken& r ): formula::FormulaToken(r) {}
62 : :
63 : : public:
64 : :
65 : : virtual ~ScToken();
66 : :
67 : : /**
68 : : Dummy methods to avoid switches and casts where possible,
69 : : the real token classes have to overload the appropriate method[s].
70 : : The only methods valid anytime if not overloaded are:
71 : :
72 : : - GetByte() since this represents the count of parameters to a function
73 : : which of course is 0 on non-functions. formula::FormulaByteToken and ScExternal do
74 : : overload it.
75 : :
76 : : - HasForceArray() since also this is only used for operators and
77 : : functions and is 0 for other tokens.
78 : :
79 : : Any other non-overloaded method pops up an assertion.
80 : : */
81 : :
82 : : virtual const ScSingleRefData& GetSingleRef() const;
83 : : virtual ScSingleRefData& GetSingleRef();
84 : : virtual const ScComplexRefData& GetDoubleRef() const;
85 : : virtual ScComplexRefData& GetDoubleRef();
86 : : virtual const ScSingleRefData& GetSingleRef2() const;
87 : : virtual ScSingleRefData& GetSingleRef2();
88 : : virtual void CalcAbsIfRel( const ScAddress& );
89 : : virtual void CalcRelFromAbs( const ScAddress& );
90 : : virtual const ScMatrix* GetMatrix() const;
91 : : virtual ScMatrix* GetMatrix();
92 : : virtual ScJumpMatrix* GetJumpMatrix() const;
93 : : virtual const ScRefList* GetRefList() const;
94 : : virtual ScRefList* GetRefList();
95 : :
96 : : virtual bool TextEqual( const formula::FormulaToken& rToken ) const;
97 : : virtual bool Is3DRef() const; // reference with 3D flag set
98 : :
99 : : /** If rTok1 and rTok2 both are SingleRef or DoubleRef tokens, extend/merge
100 : : ranges as needed for ocRange.
101 : : @param rPos
102 : : The formula's position, used to calculate absolute positions from
103 : : relative references.
104 : : @param bReuseDoubleRef
105 : : If true, a DoubleRef token is reused if passed as rTok1 or rTok2,
106 : : else a new DoubleRef token is created and returned.
107 : : @return
108 : : A reused or new'ed ScDoubleRefToken, or a NULL TokenRef if rTok1 or
109 : : rTok2 are not of sv(Single|Double)Ref
110 : : */
111 : : static formula::FormulaTokenRef ExtendRangeReference( formula::FormulaToken & rTok1, formula::FormulaToken & rTok2, const ScAddress & rPos, bool bReuseDoubleRef );
112 : : };
113 : :
114 : 27317 : inline void intrusive_ptr_add_ref(const ScToken* p)
115 : : {
116 : 27317 : p->IncRef();
117 : 27317 : }
118 : :
119 : 27317 : inline void intrusive_ptr_release(const ScToken* p)
120 : : {
121 : 27317 : p->DecRef();
122 : 27317 : }
123 : :
124 [ - + ]: 53480 : class ScSingleRefToken : public ScToken
125 : : {
126 : : private:
127 : : ScSingleRefData aSingleRef;
128 : : public:
129 : 15189 : ScSingleRefToken( const ScSingleRefData& r, OpCode e = ocPush ) :
130 : 15189 : ScToken( formula::svSingleRef, e ), aSingleRef( r ) {}
131 : 12055 : ScSingleRefToken( const ScSingleRefToken& r ) :
132 : 12055 : ScToken( r ), aSingleRef( r.aSingleRef ) {}
133 : : virtual const ScSingleRefData& GetSingleRef() const;
134 : : virtual ScSingleRefData& GetSingleRef();
135 : : virtual void CalcAbsIfRel( const ScAddress& );
136 : : virtual void CalcRelFromAbs( const ScAddress& );
137 : : virtual bool operator==( const formula::FormulaToken& rToken ) const;
138 [ + - ]: 12055 : virtual FormulaToken* Clone() const { return new ScSingleRefToken(*this); }
139 : :
140 [ + - ][ + - ]: 53984 : DECL_FIXEDMEMPOOL_NEWDEL( ScSingleRefToken );
141 : : };
142 : :
143 [ - + ]: 30854 : class ScDoubleRefToken : public ScToken
144 : : {
145 : : private:
146 : : ScComplexRefData aDoubleRef;
147 : : public:
148 : 13889 : ScDoubleRefToken( const ScComplexRefData& r, OpCode e = ocPush ) :
149 : 13889 : ScToken( formula::svDoubleRef, e ), aDoubleRef( r ) {}
150 : : ScDoubleRefToken( const ScSingleRefData& r, OpCode e = ocPush ) :
151 : : ScToken( formula::svDoubleRef, e )
152 : : {
153 : : aDoubleRef.Ref1 = r;
154 : : aDoubleRef.Ref2 = r;
155 : : }
156 : 1547 : ScDoubleRefToken( const ScDoubleRefToken& r ) :
157 : 1547 : ScToken( r ), aDoubleRef( r.aDoubleRef ) {}
158 : : virtual const ScSingleRefData& GetSingleRef() const;
159 : : virtual ScSingleRefData& GetSingleRef();
160 : : virtual const ScComplexRefData& GetDoubleRef() const;
161 : : virtual ScComplexRefData& GetDoubleRef();
162 : : virtual const ScSingleRefData& GetSingleRef2() const;
163 : : virtual ScSingleRefData& GetSingleRef2();
164 : : virtual void CalcAbsIfRel( const ScAddress& );
165 : : virtual void CalcRelFromAbs( const ScAddress& );
166 : : virtual bool operator==( const formula::FormulaToken& rToken ) const;
167 [ + - ]: 1547 : virtual FormulaToken* Clone() const { return new ScDoubleRefToken(*this); }
168 : :
169 [ + - ][ + - ]: 30863 : DECL_FIXEDMEMPOOL_NEWDEL( ScDoubleRefToken );
170 : : };
171 : :
172 [ + - ][ - + ]: 684 : class ScMatrixToken : public ScToken
173 : : {
174 : : private:
175 : : ScMatrixRef pMatrix;
176 : : public:
177 : 324 : ScMatrixToken( ScMatrixRef p ) :
178 : 324 : ScToken( formula::svMatrix ), pMatrix( p ) {}
179 : 27 : ScMatrixToken( const ScMatrixToken& r ) :
180 : 27 : ScToken( r ), pMatrix( r.pMatrix ) {}
181 : : virtual const ScMatrix* GetMatrix() const;
182 : : virtual ScMatrix* GetMatrix();
183 : : virtual bool operator==( const formula::FormulaToken& rToken ) const;
184 [ + - ]: 27 : virtual FormulaToken* Clone() const { return new ScMatrixToken(*this); }
185 : : };
186 : :
187 : :
188 : : class ScExternalSingleRefToken : public ScToken
189 : : {
190 : : private:
191 : : sal_uInt16 mnFileId;
192 : : String maTabName;
193 : : ScSingleRefData maSingleRef;
194 : :
195 : : ScExternalSingleRefToken(); // disabled
196 : : public:
197 : : ScExternalSingleRefToken( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& r );
198 : : ScExternalSingleRefToken( const ScExternalSingleRefToken& r );
199 : : virtual ~ScExternalSingleRefToken();
200 : :
201 : : virtual sal_uInt16 GetIndex() const;
202 : : virtual const String& GetString() const;
203 : : virtual const ScSingleRefData& GetSingleRef() const;
204 : : virtual ScSingleRefData& GetSingleRef();
205 : : virtual void CalcAbsIfRel( const ScAddress& );
206 : : virtual void CalcRelFromAbs( const ScAddress& );
207 : : virtual bool operator==( const formula::FormulaToken& rToken ) const;
208 [ + - ]: 4 : virtual FormulaToken* Clone() const { return new ScExternalSingleRefToken(*this); }
209 : : };
210 : :
211 : :
212 : : class ScExternalDoubleRefToken : public ScToken
213 : : {
214 : : private:
215 : : sal_uInt16 mnFileId;
216 : : String maTabName; // name of the first sheet
217 : : ScComplexRefData maDoubleRef;
218 : :
219 : : ScExternalDoubleRefToken(); // disabled
220 : : public:
221 : : ScExternalDoubleRefToken( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& r );
222 : : ScExternalDoubleRefToken( const ScExternalDoubleRefToken& r );
223 : : virtual ~ScExternalDoubleRefToken();
224 : :
225 : : virtual sal_uInt16 GetIndex() const;
226 : : virtual const String& GetString() const;
227 : : virtual const ScSingleRefData& GetSingleRef() const;
228 : : virtual ScSingleRefData& GetSingleRef();
229 : : virtual const ScSingleRefData& GetSingleRef2() const;
230 : : virtual ScSingleRefData& GetSingleRef2();
231 : : virtual const ScComplexRefData& GetDoubleRef() const;
232 : : virtual ScComplexRefData& GetDoubleRef();
233 : : virtual void CalcAbsIfRel( const ScAddress& );
234 : : virtual void CalcRelFromAbs( const ScAddress& );
235 : : virtual bool operator==( const formula::FormulaToken& rToken ) const;
236 [ # # ]: 0 : virtual FormulaToken* Clone() const { return new ScExternalDoubleRefToken(*this); }
237 : : };
238 : :
239 : : class ScExternalNameToken : public ScToken
240 : : {
241 : : private:
242 : : sal_uInt16 mnFileId;
243 : : String maName;
244 : : private:
245 : : ScExternalNameToken(); // disabled
246 : : public:
247 : : ScExternalNameToken( sal_uInt16 nFileId, const String& rName );
248 : : ScExternalNameToken( const ScExternalNameToken& r );
249 : : virtual ~ScExternalNameToken();
250 : : virtual sal_uInt16 GetIndex() const;
251 : : virtual const String& GetString() const;
252 : : virtual bool operator==( const formula::FormulaToken& rToken ) const;
253 [ # # ]: 0 : virtual FormulaToken* Clone() const { return new ScExternalNameToken(*this); }
254 : : };
255 : :
256 : :
257 : : // Only created from within the interpreter, no conversion from ScRawToken,
258 : : // never added to ScTokenArray!
259 : : class ScJumpMatrixToken : public ScToken
260 : : {
261 : : private:
262 : : ScJumpMatrix* pJumpMatrix;
263 : : public:
264 : 0 : ScJumpMatrixToken( ScJumpMatrix* p ) :
265 : 0 : ScToken( formula::svJumpMatrix ), pJumpMatrix( p ) {}
266 : 0 : ScJumpMatrixToken( const ScJumpMatrixToken& r ) :
267 : 0 : ScToken( r ), pJumpMatrix( r.pJumpMatrix ) {}
268 : : virtual ~ScJumpMatrixToken();
269 : : virtual ScJumpMatrix* GetJumpMatrix() const;
270 : : virtual bool operator==( const formula::FormulaToken& rToken ) const;
271 [ # # ]: 0 : virtual FormulaToken* Clone() const { return new ScJumpMatrixToken(*this); }
272 : : };
273 : :
274 : :
275 : : // Only created from within the interpreter, no conversion from ScRawToken,
276 : : // never added to ScTokenArray!
277 [ # # ]: 0 : class ScRefListToken : public ScToken
278 : : {
279 : : private:
280 : : ScRefList aRefList;
281 : : public:
282 : 0 : ScRefListToken() :
283 [ # # ]: 0 : ScToken( formula::svRefList ) {}
284 : 0 : ScRefListToken( const ScRefListToken & r ) :
285 [ # # ]: 0 : ScToken( r ), aRefList( r.aRefList ) {}
286 : : virtual void CalcAbsIfRel( const ScAddress& );
287 : : virtual void CalcRelFromAbs( const ScAddress& );
288 : : virtual const ScRefList* GetRefList() const;
289 : : virtual ScRefList* GetRefList();
290 : : virtual bool operator==( const formula::FormulaToken& rToken ) const;
291 [ # # ]: 0 : virtual FormulaToken* Clone() const { return new ScRefListToken(*this); }
292 : : };
293 : :
294 : :
295 [ - + ]: 120 : class SC_DLLPUBLIC ScEmptyCellToken : public ScToken
296 : : {
297 : : bool bInherited :1;
298 : : bool bDisplayedAsString :1;
299 : : public:
300 : 54 : explicit ScEmptyCellToken( bool bInheritedP, bool bDisplayAsString ) :
301 : : ScToken( formula::svEmptyCell ),
302 : : bInherited( bInheritedP ),
303 : 54 : bDisplayedAsString( bDisplayAsString ) {}
304 : 6 : ScEmptyCellToken( const ScEmptyCellToken& r ) :
305 : : ScToken( r ),
306 : : bInherited( r.bInherited ),
307 : 6 : bDisplayedAsString( r.bDisplayedAsString ) {}
308 : 0 : bool IsInherited() const { return bInherited; }
309 : 39 : bool IsDisplayedAsString() const { return bDisplayedAsString; }
310 : : virtual double GetDouble() const;
311 : : virtual const String & GetString() const;
312 : : virtual bool operator==( const formula::FormulaToken& rToken ) const;
313 [ + - ]: 6 : virtual FormulaToken* Clone() const { return new ScEmptyCellToken(*this); }
314 : : };
315 : :
316 : :
317 : : /** Transports the result from the interpreter to the formula cell. */
318 [ + - ][ + - ]: 247 : class SC_DLLPUBLIC ScMatrixCellResultToken : public ScToken
[ - + ]
319 : : {
320 : : // No non-const access implemented, silence down unxsols4 complaining about
321 : : // the public GetMatrix() hiding the one from ScToken.
322 : : virtual ScMatrix* GetMatrix();
323 : :
324 : : protected:
325 : : ScConstMatrixRef xMatrix;
326 : : formula::FormulaConstTokenRef xUpperLeft;
327 : : public:
328 : 165 : ScMatrixCellResultToken( const ScConstMatrixRef& pMat, formula::FormulaToken* pUL ) :
329 : : ScToken( formula::svMatrixCell ),
330 : 165 : xMatrix( pMat), xUpperLeft( pUL) {}
331 : 1 : ScMatrixCellResultToken( const ScMatrixCellResultToken& r ) :
332 : : ScToken( r ), xMatrix( r.xMatrix ),
333 : 1 : xUpperLeft( r.xUpperLeft ) {}
334 : : virtual double GetDouble() const;
335 : : virtual const String & GetString() const;
336 : : virtual const ScMatrix* GetMatrix() const;
337 : : virtual bool operator==( const formula::FormulaToken& rToken ) const;
338 [ # # ]: 0 : virtual FormulaToken* Clone() const { return new ScMatrixCellResultToken(*this); }
339 : 1205 : formula::StackVar GetUpperLeftType() const
340 : : {
341 : : return xUpperLeft ?
342 : 1114 : xUpperLeft->GetType() :
343 [ + + ]: 2319 : static_cast<formula::StackVar>(formula::svUnknown);
344 : : }
345 : 310 : inline formula::FormulaConstTokenRef GetUpperLeftToken() const { return xUpperLeft; }
346 : 58 : void Assign( const ScMatrixCellResultToken & r )
347 : : {
348 : 58 : xMatrix = r.xMatrix;
349 : 58 : xUpperLeft = r.xUpperLeft;
350 : 58 : }
351 : : };
352 : :
353 : :
354 : : /** Stores the matrix result at the formula cell, additionally the range the
355 : : matrix formula occupies. */
356 [ - + ]: 170 : class SC_DLLPUBLIC ScMatrixFormulaCellToken : public ScMatrixCellResultToken
357 : : {
358 : : private:
359 : : SCROW nRows;
360 : : SCCOL nCols;
361 : : public:
362 : 84 : ScMatrixFormulaCellToken( SCCOL nC, SCROW nR ) :
363 : : ScMatrixCellResultToken( NULL, NULL ),
364 [ + - ]: 84 : nRows( nR ), nCols( nC ) {}
365 : 1 : ScMatrixFormulaCellToken( const ScMatrixFormulaCellToken& r ) :
366 : : ScMatrixCellResultToken( r ),
367 : 1 : nRows( r.nRows ), nCols( r.nCols )
368 : : {
369 : : // xUpperLeft is modifiable through
370 : : // SetUpperLeftDouble(), so clone it.
371 [ + - ]: 1 : if (xUpperLeft)
372 [ + - ][ + - ]: 1 : xUpperLeft = xUpperLeft->Clone();
373 : 1 : }
374 : : virtual bool operator==( const formula::FormulaToken& rToken ) const;
375 [ # # ]: 0 : virtual FormulaToken* Clone() const { return new ScMatrixFormulaCellToken(*this); }
376 : 0 : void SetMatColsRows( SCCOL nC, SCROW nR )
377 : : {
378 : 0 : nRows = nR;
379 : 0 : nCols = nC;
380 : 0 : }
381 : 28 : void GetMatColsRows( SCCOL & nC, SCROW & nR ) const
382 : : {
383 : 28 : nR = nRows;
384 : 28 : nC = nCols;
385 : 28 : }
386 : 0 : SCCOL GetMatCols() const { return nCols; }
387 : 0 : SCROW GetMatRows() const { return nRows; }
388 : :
389 : : /** Assign matrix result, keep matrix formula
390 : : dimension. */
391 : 58 : void Assign( const ScMatrixCellResultToken & r )
392 : : {
393 : 58 : ScMatrixCellResultToken::Assign( r);
394 : 58 : }
395 : :
396 : : /** Assign any result, keep matrix formula
397 : : dimension. If token is of type
398 : : ScMatrixCellResultToken uses the
399 : : appropriate Assign() call, other tokens
400 : : are assigned to xUpperLeft and xMatrix will
401 : : be assigned NULL. */
402 : : void Assign( const formula::FormulaToken & r );
403 : :
404 : : /** Modify xUpperLeft if formula::svDouble, or create
405 : : new formula::FormulaDoubleToken if not set yet. Does
406 : : nothing if xUpperLeft is of different type! */
407 : : void SetUpperLeftDouble( double f);
408 : :
409 : : /** Reset matrix and upper left, keep matrix
410 : : formula dimension. */
411 : 0 : void ResetResult()
412 : : {
413 : 0 : xMatrix = NULL;
414 : 0 : xUpperLeft = NULL;
415 : 0 : }
416 : : };
417 : :
418 : :
419 [ + - ][ + - ]: 344 : class SC_DLLPUBLIC ScHybridCellToken : public ScToken
[ - + ]
420 : : {
421 : : private:
422 : : double fDouble;
423 : : String aString;
424 : : String aFormula;
425 : : public:
426 : 172 : ScHybridCellToken( double f,
427 : : const String & rStr,
428 : : const String & rFormula ) :
429 : : ScToken( formula::svHybridCell ),
430 : : fDouble( f ), aString( rStr ),
431 [ + - ][ + - ]: 172 : aFormula( rFormula ) {}
432 : 0 : ScHybridCellToken( const ScHybridCellToken& r ) :
433 : : ScToken( r ), fDouble( r.fDouble),
434 [ # # ][ # # ]: 0 : aString( r.aString), aFormula( r.aFormula) {}
435 : 0 : const String & GetFormula() const { return aFormula; }
436 : : virtual double GetDouble() const;
437 : : virtual const String & GetString() const;
438 : : virtual bool operator==( const formula::FormulaToken& rToken ) const;
439 [ # # ]: 0 : virtual FormulaToken* Clone() const { return new ScHybridCellToken(*this); }
440 : : };
441 : :
442 : :
443 : : // Simplify argument passing to RefUpdate methods with ScSingleRefToken or
444 : : // ScDoubleRefToken
445 : : class SingleDoubleRefModifier
446 : : {
447 : : ScComplexRefData aDub;
448 : : ScSingleRefData* pS;
449 : : ScComplexRefData* pD;
450 : :
451 : : // not implemented, prevent usage
452 : : SingleDoubleRefModifier( const SingleDoubleRefModifier& );
453 : : SingleDoubleRefModifier& operator=( const SingleDoubleRefModifier& );
454 : :
455 : : public:
456 : 3 : SingleDoubleRefModifier( ScToken& rT )
457 : : {
458 : 3 : formula::StackVar eType = rT.GetType();
459 [ # # ][ - + ]: 3 : if ( eType == formula::svSingleRef || eType == formula::svExternalSingleRef )
460 : : {
461 : 3 : pS = &rT.GetSingleRef();
462 : 3 : aDub.Ref1 = aDub.Ref2 = *pS;
463 : 3 : pD = &aDub;
464 : : }
465 : : else
466 : : {
467 : 0 : pS = 0;
468 : 0 : pD = &rT.GetDoubleRef();
469 : : }
470 : 3 : }
471 : 215 : SingleDoubleRefModifier( ScSingleRefData& rS )
472 : : {
473 : 215 : pS = &rS;
474 : 215 : aDub.Ref1 = aDub.Ref2 = *pS;
475 : 215 : pD = &aDub;
476 : 215 : }
477 : 218 : ~SingleDoubleRefModifier()
478 : : {
479 [ + - ]: 218 : if ( pS )
480 : 218 : *pS = (*pD).Ref1;
481 : 218 : }
482 : 218 : inline ScComplexRefData& Ref() { return *pD; }
483 : : };
484 : :
485 : : class SingleDoubleRefProvider
486 : : {
487 : : public:
488 : :
489 : : const ScSingleRefData& Ref1;
490 : : const ScSingleRefData& Ref2;
491 : :
492 : 30 : SingleDoubleRefProvider( const ScToken& r )
493 : 30 : : Ref1( r.GetSingleRef() ),
494 : 30 : Ref2( (r.GetType() == formula::svDoubleRef ||
495 : 15 : r.GetType() == formula::svExternalDoubleRef) ?
496 [ + + - + ]: 45 : r.GetDoubleRef().Ref2 : Ref1 )
497 : 30 : {}
498 : : SingleDoubleRefProvider( const ScSingleRefData& r )
499 : : : Ref1( r ), Ref2( r )
500 : : {}
501 : : SingleDoubleRefProvider( const ScComplexRefData& r )
502 : : : Ref1( r.Ref1 ), Ref2( r.Ref2 )
503 : : {}
504 : 30 : ~SingleDoubleRefProvider()
505 : 30 : {}
506 : : };
507 : :
508 : : #endif
509 : :
510 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|