Kaydet (Commit) ec4c6c2b authored tarafından Caolán McNamara's avatar Caolán McNamara

remove unused GenericInformation

üst 666e9661
......@@ -59,7 +59,6 @@ $(eval $(call gb_Library_add_linked_libs,tl,\
$(eval $(call gb_Library_add_exception_objects,tl,\
tools/source/communi/geninfo \
tools/source/datetime/datetime \
tools/source/datetime/tdate \
tools/source/datetime/ttime \
......@@ -163,5 +162,5 @@ endif
# tools/source/string/debugprint -DDEBUG -DEXCEPTIONS_OFF -DOSL_DEBUG_LEVEL=2 -DSHAREDLIB -DTOOLS_DLLIMPLEMENTATION -D_DLL_ -O0 -fno-exceptions -fpic -fvisibility=hidden -g
# -DOPTIMIZE
# no -DTOOLS_DLLIMPLEMENTATION on toolsdll
# -DEXCEPTIONS_OFF -fno-exceptions on geninfo datetime tdate ttime bigint color config fract gen line link poly2 svborder toolsin inetmime inetmsg inetstrm contnr mempool multisel table unqidx cachestr stream strmsys vcompat tenccvt tstring tustring testtoolloader
# -DEXCEPTIONS_OFF -fno-exceptions on datetime tdate ttime bigint color config fract gen line link poly2 svborder toolsin inetmime inetmsg inetstrm contnr mempool multisel table unqidx cachestr stream strmsys vcompat tenccvt tstring tustring testtoolloader
# vim: set noet sw=4 ts=4:
......@@ -47,7 +47,6 @@ $(eval $(call gb_Package_add_file,tools_inc,inc/tools/fontenum.hxx,tools/fontenu
$(eval $(call gb_Package_add_file,tools_inc,inc/tools/fract.hxx,tools/fract.hxx))
$(eval $(call gb_Package_add_file,tools_inc,inc/tools/fsys.hxx,tools/fsys.hxx))
$(eval $(call gb_Package_add_file,tools_inc,inc/tools/gen.hxx,tools/gen.hxx))
$(eval $(call gb_Package_add_file,tools_inc,inc/tools/geninfo.hxx,tools/geninfo.hxx))
$(eval $(call gb_Package_add_file,tools_inc,inc/tools/getprocessworkingdir.hxx,tools/getprocessworkingdir.hxx))
$(eval $(call gb_Package_add_file,tools_inc,inc/tools/globname.hxx,tools/globname.hxx))
$(eval $(call gb_Package_add_file,tools_inc,inc/tools/inetdef.hxx,tools/inetdef.hxx))
......
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2000, 2010 Oracle and/or its affiliates.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
#ifndef _BOOTSTRP_GENINFO_HXX
#define _BOOTSTRP_GENINFO_HXX
#include "tools/toolsdllapi.h"
#include <tools/string.hxx>
#include <vector>
// forwards
class GenericInformationList;
//
// class GenericInformation
//
/******************************************************************************
Purpose: holds generic informations and subinformations in a simple format
******************************************************************************/
class TOOLS_DLLPUBLIC GenericInformation : public ByteString // the key is stored in base class
{
friend class GenericInformationList; // can be child or/and parent
private:
ByteString sValue; // holds value of data
ByteString sComment;
GenericInformationList *pInfoList; // holds subinformations
GenericInformationList *pParent; // holds a pointer to parent list
// methods
void ListDeleted() { pParent = NULL; } // allowed to be accessed
// from friend class
// GenericInformationList
public:
GenericInformation( const ByteString &rKey, const ByteString &rValue,
GenericInformationList *pParentList = NULL,
GenericInformationList *pSubInfos = NULL );
GenericInformation( const GenericInformation& rInf, sal_Bool bCopySubs = sal_True);
~GenericInformation();
ByteString &GetValue() { return sValue; }
void SetValue( const ByteString &rValue ) { sValue = rValue; }
ByteString &GetComment() { return sComment; }
void SetComment( const ByteString &rComment ) { sComment = rComment; }
// this methods used to handle sub informations
sal_Bool InsertSubInfo( GenericInformation *pInfo );
// siehe GenericInformationList
sal_Bool InsertSubInfo( const ByteString &rPathKey, const ByteString &rValue,
sal_Bool bSearchByPath = sal_False, sal_Bool bNewPath = sal_False);
void RemoveSubInfo( GenericInformation *pInfo, sal_Bool bDelete = sal_False );
// void RemoveSelf( sal_Bool bDelete = sal_False ); // loescht sich selbst aus der Parentliste
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// bei bDelete = sal_True werden auch alle Sublisten UND DIE INFO SELBST geloescht.
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
GenericInformation *GetSubInfo( ByteString &rKey, sal_Bool bSearchByPath = sal_False,
sal_Bool bCreatePath = sal_False );
// path can be something like this: src370/drives/o:
void SetSubList( GenericInformationList *pSubList )
{ pInfoList = pSubList; }
GenericInformationList *GetSubList() { return pInfoList; }
};
/* diese Klasse bietet einen SemaphoreLock zum lesen (und nicht Schreiben)
* oder schreiben (und nicht lesen)
*/
class GenericLockInformation : public GenericInformation
{
public:
GenericLockInformation( const ByteString &rKey, const ByteString &rValue,
GenericInformationList *pParentList = NULL,
GenericInformationList *pSubInfos = NULL )
: GenericInformation( rKey, rValue, pParentList, pSubInfos),
aLockState( read ), nLockKey( 0 ) {};
/* bietet einen Lockmechanismus fuer exclusive Zugriffe
*
* -"writeonly" wird angesprochen, wenn von der Wurzel ausgehend
* ein Item veraendert werden soll. In der Zeit kann die Liste nicht
* gelesen werden, womit keine Inconsistenzen entstehen koennen.
*
* -"read" wird zum Normalen lesen der Infos benutzt, 90% der Betriebszeit.
* waerenddessen kann nicht geschrieben werden -> writeonly Lock.
* Ist fuer den atomaren(nicht unterbrochenen) Lesezugriff gedacht
*
* -"readonly" wird zum niederschreiben des Teilbaums benutzt, was schon mal
* 10 Minuten dauern kann. In der Zeit kann kein Writeonlylock gesetzt
* werden, aber ein rescedule. Damit koennen andere Aktionen asynchron ausgefuert
* werden, aber die Datensicherheit bleibt gewahrt
*
* Zustandsaenderung: writeonly <-> read <-> readonly
*
* nLockKey ist zum verschluesseln des LockZugriffs mit einem 32bit Wort vorgesehen.
* ist der Schluessel nicht null, so kann nur mit dem Schluessel in
* die Baumstruktur geschrieben werden.
* ist der Schluessel nLockKey Null, dann kann jeder Schreiben und die Locks loesen
*/
enum LockState{ writeonly, read, readonly };
/* der Schreibschutz darf nur aktiviert werden, wenn
* der Status auf Lesen steht
*/
sal_Bool SetWriteLock(sal_uInt32 nKey = 0) { return ((read==aLockState) &&
(aLockState=writeonly, nLockKey=nKey, sal_True)); }
/* Schreibschutz darf nur geloest werden, wenn
* der Schreibschutz drin ist, und
* entweder der LockKey Null ist(Generalschluessel) oder der Key zum LockKey passt
*/
sal_Bool ReleaseWriteLock(sal_uInt32 nKey = 0) { return ((writeonly==aLockState) &&
(!nLockKey||nKey==nLockKey) &&
(aLockState=read, nLockKey=0, sal_True)); } // setzt den zustand auf "read"
sal_Bool SetReadLock(sal_uInt32 nKey = 0) { return ((read==aLockState) &&
(aLockState=readonly, nLockKey=nKey, sal_True)); }
sal_Bool ReleaseReadLock(sal_uInt32 nKey = 0) { return ((readonly==aLockState) &&
(!nLockKey||nKey==nLockKey) &&
(aLockState=read, nLockKey=0, sal_True)); } // setzt den zustand auf "read"
LockState GetLockState() const { return aLockState; }
sal_Bool IsWriteLocked() const { return (writeonly==aLockState); }
sal_Bool IsReadLocked() const { return (readonly==aLockState); }
sal_Bool IsNotLocked() const { return (read==aLockState); }
sal_Bool IsLocker( sal_uInt32 nKey ) { return (nKey==nLockKey || !nLockKey); }
/* wenn der Schreibschutz aktiviert wurde,
* und bei vorhandenem Schreibschutz die Keys stimmen
* rufe die Parentmethode auf */
sal_Bool InsertSubInfo( GenericInformation *pInfo, sal_uInt32 nKey = 0 ) {
return ((writeonly==aLockState) &&
(!nLockKey || nKey==nLockKey) &&
(GenericInformation::InsertSubInfo( pInfo ), sal_True)); }
sal_Bool InsertSubInfo( const ByteString &rPathKey, const ByteString &rValue, sal_uInt32 nKey = 0,
sal_Bool bSearchByPath = sal_False, sal_Bool bNewPath = sal_False) {
return ((writeonly==aLockState) &&
(!nLockKey || nKey==nLockKey) &&
(GenericInformation::InsertSubInfo( rPathKey, rValue, bSearchByPath, bNewPath ), sal_True)); }
/* 29.jan.98: erweiterung um lesemoeglichkeit vom Lockclienten */
GenericInformation *GetSubInfo( ByteString &rKey, sal_Bool bSearchByPath = sal_False,
sal_Bool bCreatePath = sal_False, sal_uInt32 nKey = 0 ) {
if (writeonly==aLockState && nLockKey && nKey!=nLockKey )
return NULL;
return GenericInformation::GetSubInfo(rKey, bSearchByPath, bCreatePath); }
private:
LockState aLockState;
sal_uInt32 nLockKey;
};
//
// class GenericInformationList
//
/******************************************************************************
Purpose: holds set of generic informations in a sorted list
******************************************************************************/
typedef ::std::vector< GenericInformation* > GenericInformationList_Impl;
class TOOLS_DLLPUBLIC GenericInformationList
{
private:
GenericInformationList_Impl maList;
GenericInformation *pOwner; // holds parent of this list
protected:
// methods
size_t InsertSorted( GenericInformation *pInfo, sal_Bool bOverwrite,
size_t nStart, size_t nEnd );
GenericInformation *Search( size_t &rPos, ByteString sKey,
size_t nStart, size_t nEnd );
public:
GenericInformationList( GenericInformation *pParent = NULL );
GenericInformationList(const GenericInformationList& rList, GenericInformation *pParent = NULL);
~GenericInformationList();
// this methods used to handle the informations using binary search
GenericInformation *GetInfo( ByteString &rKey, sal_Bool bSearchByPath = sal_False,
sal_Bool bCreatePath = sal_False );
/* path can be something like this: src370/drives/o:
* bCreatePath will create the neccecary paths to the GI */
sal_Bool InsertInfo( GenericInformation *pInfo, sal_Bool bOverwrite = sal_True );
/* legt eine GenericInformation im Baum an mit Key-Value
* wenn bNewPath gesetzt, wird der nichtexistente Teil des Pfades neu kreiert
* wenn bNewPath nicht gesetzt ist und ein Teil des Pfades nicht vorhanden ist,
* gibt die Methode sal_False zurueck.*/
sal_Bool InsertInfo( const ByteString &rPathKey, const ByteString &rValue,
sal_Bool bSearchByPath = sal_False, sal_Bool bNewPath = sal_False);
void RemoveInfo( GenericInformation *pInfo, sal_Bool bDelete = sal_False );
GenericInformation* SetOwner( GenericInformation *pNewOwner );
size_t size() const;
GenericInformation* operator[]( size_t i ) const;
};
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2000, 2010 Oracle and/or its affiliates.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_tools.hxx"
#include "tools/geninfo.hxx"
#include <stdio.h>
//
// class GenericInformation
//
/*****************************************************************************/
GenericInformation::GenericInformation( const ByteString &rKey,
const ByteString &rValue,
GenericInformationList *pParentList,
GenericInformationList *pSubInfos )
/*****************************************************************************/
: ByteString( rKey ),
sValue( rValue ),
pInfoList( pSubInfos ),
pParent( pParentList )
{
// if a ParentList exists, insert this object into it
if ( pParent )
pParent->InsertInfo( this );
// make myself owner of pInfoList
if ( pInfoList )
pInfoList->SetOwner( this );
}
/*****************************************************************************/
GenericInformation::GenericInformation( const GenericInformation& rInf,
sal_Bool bCopySubs)
/*****************************************************************************/
: ByteString( rInf ),
sValue( rInf.sValue ),
pInfoList( 0L ),
pParent(NULL)
{
if(bCopySubs && rInf.pInfoList)
pInfoList = new GenericInformationList(*rInf.pInfoList, this);
}
/*****************************************************************************/
GenericInformation::~GenericInformation()
/*****************************************************************************/
{
// remove pInfoList and all childs out of memory
delete pInfoList;
pInfoList = 0;
// remove this Info out of ParentList
if ( pParent )
pParent->RemoveInfo( this );
}
/*****************************************************************************/
sal_Bool GenericInformation::InsertSubInfo( GenericInformation *pInfo )
/*****************************************************************************/
{
return ( pInfoList && pInfoList->InsertInfo( pInfo ));
}
/*****************************************************************************/
sal_Bool GenericInformation::InsertSubInfo( const ByteString &rPathKey, const ByteString &rValue,
sal_Bool bSearchByPath, sal_Bool bNewPath )
/*****************************************************************************/
{
return (pInfoList && pInfoList->InsertInfo( rPathKey, rValue, bSearchByPath, bNewPath ));
}
/*****************************************************************************/
void GenericInformation::RemoveSubInfo( GenericInformation *pInfo,
sal_Bool bDelete )
/*****************************************************************************/
{
pInfoList->RemoveInfo( pInfo, bDelete );
}
/*****************************************************************************/
GenericInformation *GenericInformation::GetSubInfo( ByteString &rKey,
sal_Bool bSearchByPath,
sal_Bool bCreatePath )
/*****************************************************************************/
{
if ( !pInfoList && bCreatePath )
pInfoList = new GenericInformationList( this );
if ( pInfoList )
return pInfoList->GetInfo( rKey, bSearchByPath, bCreatePath );
return NULL;
}
//
// class GenericInformationList
//
/*****************************************************************************/
GenericInformationList::GenericInformationList( GenericInformation *pParent )
/*****************************************************************************/
: pOwner( pParent )
{
}
/*****************************************************************************/
GenericInformationList::GenericInformationList(
const GenericInformationList& rList,
GenericInformation *pParent
)
/*****************************************************************************/
{
GenericInformation* pTemp,*pWork;
pOwner = pParent;
for( size_t i = 0; i < rList.size(); i++ )
{
pTemp = rList[ i ];
pWork = new GenericInformation(*pTemp,sal_True);
maList.push_back( pWork );
}
}
/*****************************************************************************/
GenericInformationList::~GenericInformationList()
/*****************************************************************************/
{
// delete all Informations stored in this List
for ( size_t i = 0, n = maList.size(); i < n; ++i ) {
maList[ i ]->ListDeleted();
delete maList[ i ];
}
maList.clear();
}
/*****************************************************************************/
GenericInformation *GenericInformationList::Search(
size_t &rPos,
ByteString sKey,
size_t nStart,
size_t nEnd
)
/*****************************************************************************/
{
if ( maList.empty() ) {
rPos = 0;
return NULL;
}
if ( nStart == nEnd ) {
rPos = nStart;
ByteString sCandidate = ByteString( *maList[ nStart ] );
if ( sCandidate.ToUpperAscii() == sKey.ToUpperAscii()) {
return maList[ nStart ]; // found !!!
}
else {
// requested key not found
return NULL;
}
}
// search binary in existing list
size_t nActPos = nStart + (( nEnd - nStart ) / 2 );
rPos = nActPos;
ByteString sCandidate = ByteString( *maList[ nActPos ] );
if ( sCandidate.ToUpperAscii() == sKey.ToUpperAscii() )
return maList[ nActPos ]; // found !!!
// split the list at ActPos
if ( sCandidate < sKey )
return Search( rPos, sKey, nActPos + 1, nEnd );
else
return Search( rPos, sKey, nStart, nActPos );
}
/*****************************************************************************/
GenericInformation *GenericInformationList::GetInfo( ByteString &rKey,
sal_Bool bSearchByPath,
sal_Bool bCreatePath )
/*****************************************************************************/
{
rKey.EraseLeadingChars( '/' );
rKey.EraseTrailingChars( '/' );
ByteString sKey;
if ( bSearchByPath )
sKey = rKey.GetToken( 0, '/' );
else
sKey = rKey;
size_t nPos = 0;
GenericInformation *pReturnInfo = Search( nPos, sKey, 0, maList.size() - 1 );
/* wenn kein Searchpath gesetzt und kein Returninfo vorhanden,
* gib NULL zurueck
* wenn Searchpath gesetzt und returninfo vorhanden,
* suche weiter nach unten
* wenn searchpath gesetzt kein returninfo vorhanden und newpath gesetzt,
* mache neues Verzeichniss
*/
sal_uInt16 nTokenCount = rKey.GetTokenCount('/');
// search for next key of path in next level of tree
if ( bSearchByPath && (nTokenCount > 1)) {
ByteString sPath = ByteString(rKey.Copy( sKey.Len() + 1 ));
if ( !pReturnInfo ) { // wenn kein Return, dann muss man es anlegen
if ( !bCreatePath ) // wenn aber kein Create, dann nicht anlegen
return NULL;
pReturnInfo = new GenericInformation( sKey, "", this, NULL);
pReturnInfo->SetSubList( new GenericInformationList( pReturnInfo ));
}
return pReturnInfo->GetSubInfo( sPath, sal_True, bCreatePath );
}
if ( !pReturnInfo && bCreatePath ) {
pReturnInfo = new GenericInformation ( sKey, "", this, NULL);
}
return pReturnInfo; // kann durchaus NULL sein.
}
/*****************************************************************************/
size_t GenericInformationList::InsertSorted(
GenericInformation *pInfo,
sal_Bool bOverwrite,
size_t nStart,
size_t nEnd
)
/*****************************************************************************/
{
if ( maList.empty() ) {
// empty list, so insert at first pos
maList.push_back( pInfo );
return 0;
}
ByteString sKey( pInfo->GetBuffer());
sKey.ToUpperAscii();
// Check to speed up reading a (partially) sorted list
if ( nStart == 0 && maList.size()-1 == nEnd )
{
ByteString sCandidate( *maList[ nEnd ] );
if ( sCandidate.ToUpperAscii() < sKey )
{
maList.push_back( pInfo );
return nEnd+1;
}
}
// Only one element, so insert before or after
if ( maList.size() == 1 ) {
ByteString sCandidate( *maList[ 0 ] );
if ( sCandidate.ToUpperAscii() == sKey ) {
// key allready exists in list
if ( bOverwrite ) {
if ( pInfo != maList[ 0 ] )
delete maList[ 0 ];
maList[ 0 ] = pInfo;
}
return 0;
}
else if ( sCandidate > sKey ) {
maList.insert( maList.begin(), pInfo );
return 0;
}
else {
maList.push_back( pInfo );
return 1;
}
}
size_t nActPos = nStart + (( nEnd - nStart ) / 2 );
ByteString sCandidate = ByteString( *maList[ nActPos ] );
if ( sCandidate.ToUpperAscii() == sKey ) {
// key allready exists in list
if ( bOverwrite ) {
if ( pInfo != maList[ nActPos ] )
delete maList[ nActPos ];
maList[ nActPos ] = pInfo;
}
return nActPos;
}
if ( nStart == nEnd ) {
// now more ways to search for key -> insert here
GenericInformationList_Impl::iterator it = maList.begin();
::std::advance( it, nStart );
if ( sCandidate > sKey ) {
maList.insert( it, pInfo );
return nStart;
}
else {
++it;
maList.insert( it, pInfo );
return ( nStart + 1 );
}
}
if ( nActPos == maList.size() - 1 ) {
// reached end of list -> insert here
maList.push_back( pInfo );
return ( nActPos + 1 );
}
ByteString sSecondCand = ByteString( *maList[ nActPos + 1 ] );
if (( sCandidate < sKey ) && ( sSecondCand.ToUpperAscii() > sKey )) {
// optimal position to insert object
GenericInformationList_Impl::iterator it = maList.begin();
::std::advance( it, nActPos + 1 );
maList.insert( it, pInfo );
return ( nActPos + 1 );
}
if ( sCandidate < sKey )
return InsertSorted( pInfo, bOverwrite, nActPos + 1, nEnd );
else
return InsertSorted( pInfo, bOverwrite, nStart, nActPos );
}
/*****************************************************************************/
sal_Bool GenericInformationList::InsertInfo( GenericInformation *pInfo,
sal_Bool bOverwrite )
/*****************************************************************************/
{
if ( !pInfo->Len())
return sal_False;
InsertSorted( pInfo, bOverwrite, 0, maList.size() - 1 );
return sal_True;
}
/*****************************************************************************/
sal_Bool GenericInformationList::InsertInfo( const ByteString &rPathKey, const ByteString &rValue,
sal_Bool bSearchByPath, sal_Bool bNewPath )
/*****************************************************************************/
{
GenericInformation *pInfo;
ByteString sPathKey ( rPathKey );
sPathKey.EraseLeadingChars( '/' );
sPathKey.EraseTrailingChars( '/' );
pInfo = GetInfo( sPathKey, bSearchByPath, bNewPath );
if ( pInfo ) {
pInfo->SetValue( rValue );
return sal_True;
}
return sal_False;
}
/*****************************************************************************/
void GenericInformationList::RemoveInfo( GenericInformation *pInfo,
sal_Bool bDelete )
/*****************************************************************************/
{
for (
GenericInformationList_Impl::iterator it = maList.begin();
it < maList.end();
++it
) {
if ( *it == pInfo ) {
maList.erase( it );
}
}
if ( bDelete )
delete pInfo;
}
GenericInformation* GenericInformationList::SetOwner( GenericInformation *pNewOwner )
{
GenericInformation *pOldOwner = pOwner;
if ( pOwner ) // bei parent austragen;
pOwner->SetSubList( NULL );
if ( pNewOwner )
pNewOwner->SetSubList( this );
pOwner = pNewOwner;
return pOldOwner;
}
size_t GenericInformationList::size() const {
return maList.size();
}
GenericInformation* GenericInformationList::operator[]( size_t i ) const {
return ( i < maList.size() ) ? maList[ i ] : NULL;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment