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 <osl/mutex.hxx>
30 : : #include <cppuhelper/weakagg.hxx>
31 : : #include <cppuhelper/interfacecontainer.hxx>
32 : : #include "cppuhelper/exc_hlp.hxx"
33 : :
34 : : using namespace osl;
35 : : using namespace com::sun::star::uno;
36 : :
37 : : /** */ //for docpp
38 : : namespace cppu
39 : : {
40 : :
41 : : // due to static Reflection destruction from usr, ther must be a mutex leak (#73272#)
42 : 31372657 : inline static Mutex & getWeakMutex() SAL_THROW(())
43 : : {
44 : : static Mutex * s_pMutex = 0;
45 [ + + ]: 31372657 : if (! s_pMutex)
46 [ + - ]: 742 : s_pMutex = new Mutex();
47 : 31372657 : return *s_pMutex;
48 : : }
49 : :
50 : : //------------------------------------------------------------------------
51 : : //-- OWeakConnectionPoint ----------------------------------------------------
52 : : //------------------------------------------------------------------------
53 : : class OWeakConnectionPoint : public XAdapter
54 : : {
55 : : public:
56 : : /**
57 : : Hold the weak object without an acquire (only the pointer).
58 : : */
59 : 547006 : OWeakConnectionPoint( OWeakObject* pObj ) SAL_THROW(())
60 : : : m_aRefCount( 0 )
61 : : , m_pObject(pObj)
62 [ + - ][ + - ]: 547006 : , m_aReferences( getWeakMutex() )
63 : 547006 : {}
64 : :
65 : : // XInterface
66 : : Any SAL_CALL queryInterface( const Type & rType ) throw(::com::sun::star::uno::RuntimeException);
67 : : void SAL_CALL acquire() throw();
68 : : void SAL_CALL release() throw();
69 : :
70 : : // XAdapter
71 : : ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL queryAdapted() throw(::com::sun::star::uno::RuntimeException);
72 : : void SAL_CALL addReference( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XReference >& xRef ) throw(::com::sun::star::uno::RuntimeException);
73 : : void SAL_CALL removeReference( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XReference >& xRef ) throw(::com::sun::star::uno::RuntimeException);
74 : :
75 : : /// Called from the weak object if the reference count goes to zero.
76 : : void SAL_CALL dispose() throw(::com::sun::star::uno::RuntimeException);
77 : :
78 : : private:
79 : : OWeakConnectionPoint(OWeakConnectionPoint &); // not defined
80 : : void operator =(OWeakConnectionPoint &); // not defined
81 : :
82 [ + - ][ - + ]: 1081214 : virtual ~OWeakConnectionPoint() {}
83 : :
84 : : /// The reference counter.
85 : : oslInterlockedCount m_aRefCount;
86 : : /// The weak object
87 : : OWeakObject* m_pObject;
88 : : /// The container to hold the weak references
89 : : OInterfaceContainerHelper m_aReferences;
90 : : };
91 : :
92 : : // XInterface
93 : 0 : Any SAL_CALL OWeakConnectionPoint::queryInterface( const Type & rType )
94 : : throw(com::sun::star::uno::RuntimeException)
95 : : {
96 : : return ::cppu::queryInterface(
97 : 0 : rType, static_cast< XAdapter * >( this ), static_cast< XInterface * >( this ) );
98 : : }
99 : :
100 : : // XInterface
101 : 7158598 : void SAL_CALL OWeakConnectionPoint::acquire() throw()
102 : : {
103 : 7158598 : osl_incrementInterlockedCount( &m_aRefCount );
104 : 7158599 : }
105 : :
106 : : // XInterface
107 : 7141504 : void SAL_CALL OWeakConnectionPoint::release() throw()
108 : : {
109 [ + + ]: 7141504 : if (! osl_decrementInterlockedCount( &m_aRefCount ))
110 [ + - ]: 540607 : delete this;
111 : 7141504 : }
112 : :
113 : 540607 : void SAL_CALL OWeakConnectionPoint::dispose() throw(::com::sun::star::uno::RuntimeException)
114 : : {
115 : 540607 : Any ex;
116 [ + - ]: 540607 : OInterfaceIteratorHelper aIt( m_aReferences );
117 [ + + ]: 1039928 : while( aIt.hasMoreElements() )
118 : : {
119 : : try
120 : : {
121 [ + - ][ + - ]: 499321 : ((XReference *)aIt.next())->dispose();
122 : : }
123 [ # # ]: 0 : catch (com::sun::star::lang::DisposedException &) {}
124 [ # # # # : 0 : catch (RuntimeException &)
# ]
125 : : {
126 [ # # ]: 0 : ex = cppu::getCaughtException();
127 : : }
128 : : }
129 [ - + ]: 540607 : if (ex.hasValue())
130 : : {
131 [ # # ]: 0 : cppu::throwException(ex);
132 [ + - ]: 540607 : }
133 : 540607 : }
134 : :
135 : : // XInterface
136 : 3192232 : Reference< XInterface > SAL_CALL OWeakConnectionPoint::queryAdapted() throw(::com::sun::star::uno::RuntimeException)
137 : : {
138 : 3192232 : Reference< XInterface > ret;
139 : :
140 [ + - ][ + - ]: 3192232 : ClearableMutexGuard guard(getWeakMutex());
141 : :
142 [ + - ]: 3192232 : if (m_pObject)
143 : : {
144 [ + - ]: 3192232 : oslInterlockedCount n = osl_incrementInterlockedCount( &m_pObject->m_refCount );
145 : :
146 [ + + ]: 3192232 : if (n > 1)
147 : : {
148 : : // The refence is incremented. The object cannot be destroyed.
149 : : // Release the guard at the earliest point.
150 [ + - ]: 3183451 : guard.clear();
151 : : // WeakObject has a (XInterface *) cast operator
152 [ + - ][ + - ]: 3183451 : ret = *m_pObject;
153 [ + - ]: 3183451 : n = osl_decrementInterlockedCount( &m_pObject->m_refCount );
154 : : }
155 : : else
156 : : // Another thread wait in the dispose method at the guard
157 [ + - ]: 8781 : n = osl_decrementInterlockedCount( &m_pObject->m_refCount );
158 : : }
159 : :
160 [ + - ]: 3192232 : return ret;
161 : : }
162 : :
163 : : // XInterface
164 : 1460020 : void SAL_CALL OWeakConnectionPoint::addReference(const Reference< XReference >& rRef)
165 : : throw(::com::sun::star::uno::RuntimeException)
166 : : {
167 : 1460020 : m_aReferences.addInterface( (const Reference< XInterface > &)rRef );
168 : 1460020 : }
169 : :
170 : : // XInterface
171 : 1449326 : void SAL_CALL OWeakConnectionPoint::removeReference(const Reference< XReference >& rRef)
172 : : throw(::com::sun::star::uno::RuntimeException)
173 : : {
174 : 1449326 : m_aReferences.removeInterface( (const Reference< XInterface > &)rRef );
175 : 1449326 : }
176 : :
177 : :
178 : : //------------------------------------------------------------------------
179 : : //-- OWeakObject -------------------------------------------------------
180 : : //------------------------------------------------------------------------
181 : :
182 : : #ifdef _MSC_VER
183 : : // Accidentally occurs in msvc mapfile = > had to be outlined.
184 : : OWeakObject::OWeakObject() SAL_THROW(())
185 : : : m_refCount( 0 ),
186 : : m_pWeakConnectionPoint( 0 )
187 : : {
188 : : }
189 : : #endif
190 : :
191 : : // XInterface
192 : 5948457 : Any SAL_CALL OWeakObject::queryInterface( const Type & rType ) throw(::com::sun::star::uno::RuntimeException)
193 : : {
194 : : return ::cppu::queryInterface(
195 : : rType,
196 : 5948457 : static_cast< XWeak * >( this ), static_cast< XInterface * >( this ) );
197 : : }
198 : :
199 : : // XInterface
200 : 154106358 : void SAL_CALL OWeakObject::acquire() throw()
201 : : {
202 : 154106358 : osl_incrementInterlockedCount( &m_refCount );
203 : 154106986 : }
204 : :
205 : : // XInterface
206 : 139602326 : void SAL_CALL OWeakObject::release() throw()
207 : : {
208 [ + + ]: 139602326 : if (osl_decrementInterlockedCount( &m_refCount ) == 0) {
209 : : // notify/clear all weak-refs before object's dtor is executed
210 : : // (which may check weak-refs to this object):
211 : 11802350 : disposeWeakConnectionPoint();
212 : : // destroy object:
213 [ + - ]: 11802350 : delete this;
214 : : }
215 : 139603019 : }
216 : :
217 : 12679669 : void OWeakObject::disposeWeakConnectionPoint()
218 : : {
219 : : OSL_PRECOND( m_refCount == 0, "OWeakObject::disposeWeakConnectionPoint: only to be called with a ref count of 0!" );
220 [ + + ]: 12679669 : if (m_pWeakConnectionPoint != 0) {
221 : 540607 : OWeakConnectionPoint * const p = m_pWeakConnectionPoint;
222 : 540607 : m_pWeakConnectionPoint = 0;
223 : : try {
224 [ + - ]: 540607 : p->dispose();
225 : : }
226 : 0 : catch (RuntimeException const& exc) {
227 : : OSL_FAIL(
228 : : OUStringToOString(
229 : : exc.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
230 : : static_cast<void>(exc);
231 : : }
232 : 540607 : p->release();
233 : : }
234 [ # # ]: 12679669 : }
235 : :
236 : 12429436 : OWeakObject::~OWeakObject() SAL_THROW( (RuntimeException) )
237 : : {
238 [ - + ]: 12429451 : }
239 : :
240 : : // XWeak
241 : 1460020 : Reference< XAdapter > SAL_CALL OWeakObject::queryAdapter()
242 : : throw (::com::sun::star::uno::RuntimeException)
243 : : {
244 [ + + ]: 1460020 : if (!m_pWeakConnectionPoint)
245 : : {
246 : : // only acquire mutex if member is not created
247 [ + - ][ + - ]: 547006 : MutexGuard aGuard( getWeakMutex() );
248 [ + - ]: 547006 : if( !m_pWeakConnectionPoint )
249 : : {
250 [ + - ][ + - ]: 547006 : OWeakConnectionPoint * p = new OWeakConnectionPoint(this);
251 : 547006 : p->acquire();
252 : 547006 : m_pWeakConnectionPoint = p;
253 [ + - ]: 547006 : }
254 : : }
255 : :
256 : 1460020 : return m_pWeakConnectionPoint;
257 : : }
258 : :
259 : : //------------------------------------------------------------------------
260 : : //-- OWeakAggObject ----------------------------------------------------
261 : : //------------------------------------------------------------------------
262 [ + - ]: 484118 : OWeakAggObject::~OWeakAggObject() SAL_THROW( (RuntimeException) )
263 : : {
264 [ - + ]: 484118 : }
265 : :
266 : : // XInterface
267 : 9381830 : void OWeakAggObject::acquire() throw()
268 : : {
269 [ + - ]: 9381830 : Reference<XInterface > x( xDelegator );
270 [ + + ]: 9381832 : if (x.is())
271 [ + - ]: 411468 : x->acquire();
272 : : else
273 : 9381832 : OWeakObject::acquire();
274 : 9381832 : }
275 : :
276 : : // XInterface
277 : 8857644 : void OWeakAggObject::release() throw()
278 : : {
279 [ + - ]: 8857644 : Reference<XInterface > x( xDelegator );
280 [ + + ]: 8857644 : if (x.is())
281 [ + - ]: 411244 : x->release();
282 : : else
283 : 8857645 : OWeakObject::release();
284 : 8857645 : }
285 : :
286 : : // XInterface
287 : 2222822 : Any OWeakAggObject::queryInterface( const Type & rType ) throw(::com::sun::star::uno::RuntimeException)
288 : : {
289 [ + - ]: 2222822 : Reference< XInterface > x( xDelegator ); // harden ref
290 [ + + ][ + - ]: 2222822 : return (x.is() ? x->queryInterface( rType ) : queryAggregation( rType ));
[ + - ][ + - ]
291 : : }
292 : :
293 : : // XAggregation
294 : 911045 : Any OWeakAggObject::queryAggregation( const Type & rType ) throw(::com::sun::star::uno::RuntimeException)
295 : : {
296 : : return ::cppu::queryInterface(
297 : : rType,
298 : : static_cast< XInterface * >( static_cast< OWeakObject * >( this ) ),
299 : : static_cast< XAggregation * >( this ),
300 : 911045 : static_cast< XWeak * >( this ) );
301 : : }
302 : :
303 : : // XAggregation
304 : 14492 : void OWeakAggObject::setDelegator( const Reference<XInterface > & rDelegator ) throw(::com::sun::star::uno::RuntimeException)
305 : : {
306 : 14492 : xDelegator = rDelegator;
307 : 14492 : }
308 : :
309 : : }
310 : :
311 : : /** */ //for docpp
312 : : namespace com
313 : : {
314 : : /** */ //for docpp
315 : : namespace sun
316 : : {
317 : : /** */ //for docpp
318 : : namespace star
319 : : {
320 : : /** */ //for docpp
321 : : namespace uno
322 : : {
323 : :
324 : :
325 : : //------------------------------------------------------------------------
326 : : //-- OWeakRefListener -----------------------------------------------------
327 : : //------------------------------------------------------------------------
328 : : class OWeakRefListener : public XReference
329 : : {
330 : : public:
331 : : OWeakRefListener(const OWeakRefListener& rRef) SAL_THROW(());
332 : : OWeakRefListener(const Reference< XInterface >& xInt) SAL_THROW(());
333 : : virtual ~OWeakRefListener() SAL_THROW(());
334 : :
335 : : // XInterface
336 : : Any SAL_CALL queryInterface( const Type & rType ) throw(RuntimeException);
337 : : void SAL_CALL acquire() throw();
338 : : void SAL_CALL release() throw();
339 : :
340 : : // XReference
341 : : void SAL_CALL dispose() throw(::com::sun::star::uno::RuntimeException);
342 : :
343 : : /// The reference counter.
344 : : oslInterlockedCount m_aRefCount;
345 : : /// The connection point of the weak object
346 : : Reference< XAdapter > m_XWeakConnectionPoint;
347 : :
348 : : private:
349 : : OWeakRefListener& SAL_CALL operator=(const OWeakRefListener& rRef) SAL_THROW(());
350 : : };
351 : :
352 : 0 : OWeakRefListener::OWeakRefListener(const OWeakRefListener& rRef) SAL_THROW(())
353 : : : com::sun::star::uno::XReference()
354 : 0 : , m_aRefCount( 1 )
355 : : {
356 : : try
357 : : {
358 [ # # ]: 0 : m_XWeakConnectionPoint = rRef.m_XWeakConnectionPoint;
359 : :
360 [ # # ]: 0 : if (m_XWeakConnectionPoint.is())
361 : : {
362 [ # # ][ # # ]: 0 : m_XWeakConnectionPoint->addReference((XReference*)this);
[ # # ][ # # ]
363 : : }
364 : : }
365 [ # # ]: 0 : catch (RuntimeException &) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
366 [ # # ]: 0 : osl_decrementInterlockedCount( &m_aRefCount );
367 : 0 : }
368 : :
369 : 1460020 : OWeakRefListener::OWeakRefListener(const Reference< XInterface >& xInt) SAL_THROW(())
370 : 1460020 : : m_aRefCount( 1 )
371 : : {
372 : : try
373 : : {
374 [ + - ]: 1460020 : Reference< XWeak > xWeak( Reference< XWeak >::query( xInt ) );
375 : :
376 [ + - ]: 1460020 : if (xWeak.is())
377 : : {
378 [ + - ][ + - ]: 1460020 : m_XWeakConnectionPoint = xWeak->queryAdapter();
[ + - ]
379 : :
380 [ + - ]: 1460020 : if (m_XWeakConnectionPoint.is())
381 : : {
382 [ + - ][ + - ]: 1460020 : m_XWeakConnectionPoint->addReference((XReference*)this);
[ + - ]
383 : : }
384 [ # # ]: 1460020 : }
385 : : }
386 [ # # ]: 0 : catch (RuntimeException &) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
387 [ + - ]: 1460020 : osl_decrementInterlockedCount( &m_aRefCount );
388 : 1460020 : }
389 : :
390 : 1447823 : OWeakRefListener::~OWeakRefListener() SAL_THROW(())
391 : : {
392 : : try
393 : : {
394 [ - + ]: 1447823 : if (m_XWeakConnectionPoint.is())
395 : : {
396 : 0 : acquire(); // dont die again
397 [ # # ][ # # ]: 0 : m_XWeakConnectionPoint->removeReference((XReference*)this);
[ # # ][ # # ]
398 : : }
399 : : }
400 [ # # ]: 0 : catch (RuntimeException &) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
401 [ - + ]: 2895646 : }
402 : :
403 : : // XInterface
404 : 0 : Any SAL_CALL OWeakRefListener::queryInterface( const Type & rType ) throw(RuntimeException)
405 : : {
406 : : return ::cppu::queryInterface(
407 : 0 : rType, static_cast< XReference * >( this ), static_cast< XInterface * >( this ) );
408 : : }
409 : :
410 : : // XInterface
411 : 9589578 : void SAL_CALL OWeakRefListener::acquire() throw()
412 : : {
413 : 9589578 : osl_incrementInterlockedCount( &m_aRefCount );
414 : 9589578 : }
415 : :
416 : : // XInterface
417 : 9566687 : void SAL_CALL OWeakRefListener::release() throw()
418 : : {
419 [ + + ]: 9566687 : if( ! osl_decrementInterlockedCount( &m_aRefCount ) )
420 [ + - ]: 1447823 : delete this;
421 : 9566687 : }
422 : :
423 : 499321 : void SAL_CALL OWeakRefListener::dispose()
424 : : throw(::com::sun::star::uno::RuntimeException)
425 : : {
426 : 499321 : Reference< XAdapter > xAdp;
427 : : {
428 [ + - ][ + - ]: 499321 : MutexGuard guard(cppu::getWeakMutex());
429 [ + - ]: 499321 : if( m_XWeakConnectionPoint.is() )
430 : : {
431 [ + - ]: 499321 : xAdp = m_XWeakConnectionPoint;
432 : 499321 : m_XWeakConnectionPoint.clear();
433 [ + - ]: 499321 : }
434 : : }
435 : :
436 [ + - ]: 499321 : if( xAdp.is() )
437 [ + - ][ + - ]: 499321 : xAdp->removeReference((XReference*)this);
[ + - ]
438 : 499321 : }
439 : :
440 : : //------------------------------------------------------------------------
441 : : //-- WeakReferenceHelper ----------------------------------------------------------
442 : : //------------------------------------------------------------------------
443 : 271329 : WeakReferenceHelper::WeakReferenceHelper(const Reference< XInterface >& xInt) SAL_THROW(())
444 : 271329 : : m_pImpl( 0 )
445 : : {
446 [ + + ]: 271329 : if (xInt.is())
447 : : {
448 [ + - ]: 268301 : m_pImpl = new OWeakRefListener(xInt);
449 : 268301 : m_pImpl->acquire();
450 : : }
451 : 271330 : }
452 : :
453 : 780413 : WeakReferenceHelper::WeakReferenceHelper(const WeakReferenceHelper& rWeakRef) SAL_THROW(())
454 : 780413 : : m_pImpl( 0 )
455 : : {
456 [ + - ]: 780413 : Reference< XInterface > xInt( rWeakRef.get() );
457 [ + + ]: 780413 : if (xInt.is())
458 : : {
459 [ + - ][ + - ]: 704215 : m_pImpl = new OWeakRefListener(xInt);
460 : 704215 : m_pImpl->acquire();
461 : 780413 : }
462 : 780413 : }
463 : :
464 : 2913488 : void WeakReferenceHelper::clear() SAL_THROW(())
465 : : {
466 : : try
467 : : {
468 [ + + ]: 2913488 : if (m_pImpl)
469 : : {
470 [ + + ]: 1447823 : if (m_pImpl->m_XWeakConnectionPoint.is())
471 : : {
472 [ + - ]: 950005 : m_pImpl->m_XWeakConnectionPoint->removeReference(
473 [ + - ][ + - ]: 950005 : (XReference*)m_pImpl);
[ # # ]
474 : 950005 : m_pImpl->m_XWeakConnectionPoint.clear();
475 : : }
476 : 1447823 : m_pImpl->release();
477 : 1447823 : m_pImpl = 0;
478 : : }
479 : : }
480 : 0 : catch (RuntimeException &) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
481 : 2913488 : }
482 : :
483 : 25099 : WeakReferenceHelper& WeakReferenceHelper::operator=(const WeakReferenceHelper& rWeakRef) SAL_THROW(())
484 : : {
485 [ - + ]: 25099 : if (this == &rWeakRef)
486 : : {
487 : 0 : return *this;
488 : : }
489 [ + - ]: 25099 : Reference< XInterface > xInt( rWeakRef.get() );
490 [ + - ]: 25099 : return operator = ( xInt );
491 : : }
492 : :
493 : : WeakReferenceHelper & SAL_CALL
494 : 655999 : WeakReferenceHelper::operator= (const Reference< XInterface > & xInt)
495 : : SAL_THROW(())
496 : : {
497 : : try
498 : : {
499 [ + - ]: 655999 : clear();
500 [ + + ]: 655999 : if (xInt.is())
501 : : {
502 [ + - ]: 487504 : m_pImpl = new OWeakRefListener(xInt);
[ + - # # ]
503 : 487504 : m_pImpl->acquire();
504 : : }
505 : : }
506 : 0 : catch (RuntimeException &) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
507 : 655999 : return *this;
508 : : }
509 : :
510 : 2255593 : WeakReferenceHelper::~WeakReferenceHelper() SAL_THROW(())
511 : : {
512 : 2255593 : clear();
513 : 2255593 : }
514 : :
515 : 26587101 : Reference< XInterface > WeakReferenceHelper::get() const SAL_THROW(())
516 : : {
517 : : try
518 : : {
519 : 26587101 : Reference< XAdapter > xAdp;
520 : : {
521 [ + - ][ + - ]: 26587109 : MutexGuard guard(cppu::getWeakMutex());
522 [ + + ][ + + ]: 26587115 : if( m_pImpl && m_pImpl->m_XWeakConnectionPoint.is() )
[ + + ]
523 [ + - ][ + - ]: 26587115 : xAdp = m_pImpl->m_XWeakConnectionPoint;
524 : : }
525 : :
526 [ + + ]: 26587115 : if (xAdp.is())
527 [ + - ][ + - ]: 26587115 : return xAdp->queryAdapted();
[ + + ][ # # ]
528 : : }
529 : 0 : catch (RuntimeException &) { OSL_ASSERT( 0 ); } // assert here, but no unexpected()
530 : :
531 : 26587115 : return Reference< XInterface >();
532 : : }
533 : :
534 : : }
535 : : }
536 : : }
537 : : }
538 : :
539 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|