We can't run them in the normal way, but we build the tests as static archives, which we link into the single sal_cppunittester_all executable. (Work in progress, so far just a part of the tests are linked into it.) There is no makefilery yet to actually construct a complete iOS app bundle (.app directory), so just copy (in this case) the sal_cppunittester_all iOS executable on top of the executbale some dummy iOS app you build in Xcode... works fine, can be debugged that way.
532 lines
19 KiB
C++
532 lines
19 KiB
C++
/* -*- 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_sal.hxx"
|
|
|
|
//------------------------------------------------------------------------
|
|
// include files
|
|
//------------------------------------------------------------------------
|
|
#include <osl_Module_Const.h>
|
|
|
|
using namespace osl;
|
|
|
|
using ::rtl::OUString;
|
|
using ::rtl::OUStringToOString;
|
|
using ::rtl::OString;
|
|
//------------------------------------------------------------------------
|
|
// helper functions and classes
|
|
//------------------------------------------------------------------------
|
|
|
|
/** print Boolean value.
|
|
*/
|
|
inline void printBool( sal_Bool bOk )
|
|
{
|
|
printf("#printBool# " );
|
|
( sal_True == bOk ) ? printf( "TRUE!\n" )
|
|
: printf( "FALSE!\n" );
|
|
}
|
|
|
|
/** print a UNI_CODE String.
|
|
*/
|
|
inline void printUString( const ::rtl::OUString & str )
|
|
{
|
|
rtl::OString aString;
|
|
|
|
printf("#printUString_u# " );
|
|
aString = ::rtl::OUStringToOString( str, RTL_TEXTENCODING_ASCII_US );
|
|
printf("%s\n", aString.getStr( ) );
|
|
}
|
|
|
|
/** get dll file URL.
|
|
*/
|
|
inline ::rtl::OUString getDllURL( void )
|
|
{
|
|
#if ( defined WNT ) // lib in Unix and lib in Windows are not same in file name.
|
|
::rtl::OUString libPath( RTL_CONSTASCII_USTRINGPARAM("Module_DLL.dll") );
|
|
#else
|
|
::rtl::OUString libPath( RTL_CONSTASCII_USTRINGPARAM("libModule_DLL.so") );
|
|
#endif
|
|
|
|
::rtl::OUString dirPath, dllPath;
|
|
osl::Module::getUrlFromAddress( ( void* ) &getDllURL, dirPath );
|
|
dirPath = dirPath.copy( 0, dirPath.lastIndexOf('/') + 1);
|
|
osl::FileBase::getAbsoluteFileURL( dirPath, libPath, dllPath );
|
|
|
|
return dllPath;
|
|
}
|
|
|
|
inline sal_Bool isURL( const ::rtl::OUString pathname )
|
|
{
|
|
::rtl::OUString aPreURL( RTL_CONSTASCII_USTRINGPARAM("file:///") );
|
|
return ( ( pathname.indexOf( aPreURL ) == 0 ) ? sal_True : sal_False );
|
|
}
|
|
|
|
/** create a temp test directory using OUString name of full qualified URL or system path.
|
|
*/
|
|
inline void createTestDirectory( const ::rtl::OUString dirname )
|
|
{
|
|
::rtl::OUString aPathURL = dirname.copy( 0 );
|
|
::osl::FileBase::RC nError;
|
|
|
|
if ( !isURL( dirname ) )
|
|
::osl::FileBase::getFileURLFromSystemPath( dirname, aPathURL ); //convert if not full qualified URL
|
|
nError = ::osl::Directory::create( aPathURL );
|
|
CPPUNIT_ASSERT_MESSAGE( "In createTestDirectory Function: creation: ", ( ::osl::FileBase::E_None == nError ) || ( nError == ::osl::FileBase::E_EXIST ) );
|
|
}
|
|
|
|
/** delete a temp test directory using OUString name of full qualified URL or system path.
|
|
*/
|
|
inline void deleteTestDirectory( const ::rtl::OUString dirname )
|
|
{
|
|
::rtl::OUString aPathURL = dirname.copy( 0 );
|
|
::osl::FileBase::RC nError;
|
|
if ( !isURL( dirname ) )
|
|
::osl::FileBase::getFileURLFromSystemPath( dirname, aPathURL ); //convert if not full qualified URL
|
|
|
|
::osl::Directory testDir( aPathURL );
|
|
if ( testDir.isOpen( ) == sal_True )
|
|
{
|
|
testDir.close( ); //close if still open.
|
|
}
|
|
|
|
nError = ::osl::Directory::remove( aPathURL );
|
|
CPPUNIT_ASSERT_MESSAGE( "In deleteTestDirectory function: remove ", ( ::osl::FileBase::E_None == nError ) || ( nError == ::osl::FileBase::E_NOENT ) );
|
|
}
|
|
|
|
//check if the file exist
|
|
inline sal_Bool ifFileExist( const ::rtl::OUString & str )
|
|
{
|
|
::rtl::OUString aUStr;
|
|
if ( isURL( str ) )
|
|
::osl::FileBase::getSystemPathFromFileURL( str, aUStr );
|
|
else
|
|
return sal_False;
|
|
|
|
::osl::File strFile( aUStr );
|
|
::osl::FileBase::RC nError = strFile.open( osl_File_OpenFlag_Read );
|
|
if ( ::File::E_NOENT == nError )
|
|
return sal_False;
|
|
else{
|
|
strFile.close( );
|
|
return sal_True;
|
|
}
|
|
}
|
|
|
|
/** detete a temp test file using OUString name.
|
|
*/
|
|
inline void deleteTestFile( const ::rtl::OUString filename )
|
|
{
|
|
::rtl::OUString aPathURL = filename.copy( 0 );
|
|
::osl::FileBase::RC nError;
|
|
|
|
if ( !isURL( filename ) )
|
|
::osl::FileBase::getFileURLFromSystemPath( filename, aPathURL ); //convert if not full qualified URL
|
|
|
|
nError = ::osl::File::setAttributes( aPathURL, osl_File_Attribute_GrpWrite| osl_File_Attribute_OwnWrite| osl_File_Attribute_OthWrite ); // if readonly, make writtenable.
|
|
CPPUNIT_ASSERT_MESSAGE( "In deleteTestFile Function: set writtenable ", ( ::osl::FileBase::E_None == nError ) || ( ::osl::FileBase::E_NOENT == nError ) );
|
|
|
|
nError = ::osl::File::remove( aPathURL );
|
|
CPPUNIT_ASSERT_MESSAGE( "In deleteTestFile Function: remove ", ( ::osl::FileBase::E_None == nError ) || ( nError == ::osl::FileBase::E_NOENT ) );
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
// test code start here
|
|
//------------------------------------------------------------------------
|
|
|
|
namespace osl_Module
|
|
{
|
|
|
|
/** class and member function that is available for module test :
|
|
*/
|
|
|
|
class testClass
|
|
{
|
|
public:
|
|
static void myFunc()
|
|
{
|
|
printf("#Sun Microsystem\n");
|
|
};
|
|
};
|
|
|
|
|
|
/** testing the methods:
|
|
Module();
|
|
Module( const ::rtl::OUString& strModuleName, sal_Int32 nRtldMode = SAL_LOADMODULE_DEFAULT);
|
|
*/
|
|
class ctors : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
sal_Bool bRes, bRes1;
|
|
|
|
void ctors_none( )
|
|
{
|
|
::osl::Module aMod;
|
|
bRes = aMod.is();
|
|
|
|
printf ("Here we are\n");
|
|
|
|
CPPUNIT_ASSERT_MESSAGE( "#test comment#: test constructor without parameter.",
|
|
sal_False == bRes );
|
|
}
|
|
|
|
void ctors_name_mode( )
|
|
{
|
|
OUString aFileURL;
|
|
bRes = osl::Module::getUrlFromAddress( ( void* ) &::osl_Module::testClass::myFunc, aFileURL );
|
|
|
|
if ( !( bRes ) )
|
|
{
|
|
CPPUNIT_ASSERT_MESSAGE("Cannot locate current module.", sal_False );
|
|
}
|
|
|
|
::osl::Module aMod( aFileURL );
|
|
bRes = aMod.is( );
|
|
aMod.unload( );
|
|
|
|
CPPUNIT_ASSERT_MESSAGE( "#test comment#: test constructor with load action.",
|
|
sal_True == bRes );
|
|
}
|
|
|
|
CPPUNIT_TEST_SUITE( ctors );
|
|
CPPUNIT_TEST( ctors_none );
|
|
CPPUNIT_TEST( ctors_name_mode );
|
|
CPPUNIT_TEST_SUITE_END( );
|
|
}; // class ctors
|
|
|
|
|
|
/** testing the methods:
|
|
static sal_Bool getUrlFromAddress(void * addr, ::rtl::OUString & libraryUrl)
|
|
*/
|
|
class getUrlFromAddress : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
sal_Bool bRes, bRes1;
|
|
|
|
void getUrlFromAddress_001( )
|
|
{
|
|
OUString aFileURL;
|
|
bRes = osl::Module::getUrlFromAddress( ( void* ) &::osl_Module::testClass::myFunc, aFileURL ) ;
|
|
if ( !( bRes ) )
|
|
{
|
|
CPPUNIT_ASSERT_MESSAGE("Cannot locate current module.", sal_False );
|
|
}
|
|
|
|
CPPUNIT_ASSERT_MESSAGE( "#test comment#: test get Module URL from address.",
|
|
sal_True == bRes && 0 < aFileURL.lastIndexOf('/') );
|
|
}
|
|
|
|
void getUrlFromAddress_002( )
|
|
{
|
|
#if !defined( MACOSX )
|
|
// TODO: Find out why this fails on Mac OS X
|
|
::osl::Module aMod( getDllURL( ) );
|
|
FuncPtr pFunc = ( FuncPtr ) aMod.getSymbol( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("firstfunc")) );
|
|
|
|
OUString aFileURL;
|
|
bRes = osl::Module::getUrlFromAddress( ( void* )pFunc, aFileURL );
|
|
if ( !( bRes ) )
|
|
{
|
|
CPPUNIT_ASSERT_MESSAGE("Cannot locate current module.", sal_False );
|
|
}
|
|
aMod.unload( );
|
|
|
|
CPPUNIT_ASSERT_MESSAGE( "#test comment#: load an external library, get its function address and get its URL.",
|
|
sal_True == bRes && 0 < aFileURL.lastIndexOf('/') && aFileURL.equalsIgnoreAsciiCase( getDllURL( ) ) );
|
|
#endif
|
|
}
|
|
|
|
/* tester comments: another case is getFunctionSymbol_001*/
|
|
|
|
CPPUNIT_TEST_SUITE( getUrlFromAddress );
|
|
CPPUNIT_TEST( getUrlFromAddress_001 );
|
|
CPPUNIT_TEST( getUrlFromAddress_002 );
|
|
CPPUNIT_TEST_SUITE_END( );
|
|
}; // class getUrlFromAddress
|
|
|
|
|
|
/** testing the method:
|
|
sal_Bool SAL_CALL load( const ::rtl::OUString& strModuleName,
|
|
sal_Int32 nRtldMode = SAL_LOADMODULE_DEFAULT)
|
|
*/
|
|
class load : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
sal_Bool bRes, bRes1;
|
|
|
|
void load_001( )
|
|
{
|
|
::osl::Module aMod( getDllURL( ) );
|
|
::osl::Module aMod1;
|
|
|
|
aMod1.load( getDllURL( ) );
|
|
bRes = oslModule(aMod) == oslModule(aMod1);
|
|
aMod.unload( );
|
|
aMod1.unload( );
|
|
|
|
CPPUNIT_ASSERT_MESSAGE( "#test comment#: load function should do the same thing as constructor with library name.",
|
|
sal_True == bRes );
|
|
}
|
|
// load lib which is under a CJK directory
|
|
void load_002( )
|
|
{
|
|
#if defined( UNX ) && !defined( MACOSX )
|
|
// TODO: Find out why this fails on Mac OS X
|
|
//Can not get a CJK directory already exist, so here create one. Perhaps reason is encoding problem.
|
|
::rtl::OUString aPidDirURL = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("file:///tmp/")) + ::rtl::OUString::valueOf( ( long )getpid( ) );
|
|
::rtl::OUString aMyDirURL = aPidDirURL + aKname;
|
|
createTestDirectory( aPidDirURL );
|
|
createTestDirectory( aMyDirURL );
|
|
|
|
::rtl::OUString aDLLURL = aMyDirURL + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/libModule_DLL.so"));
|
|
//check if the lib exist.
|
|
//FIXME: if assert condition is false, the case will return, so the directory will not be clean-up
|
|
CPPUNIT_ASSERT_MESSAGE( "#Source file is not exist. please manually clean-up directory and file under /tmp", ifFileExist( getDllURL( ) ) == sal_True );
|
|
::osl::FileBase::RC nError = ::osl::File::copy( getDllURL( ), aDLLURL );
|
|
CPPUNIT_ASSERT_MESSAGE( "#copy failed. please manually clean-up directory and file under /tmp", nError == ::osl::FileBase::E_None );
|
|
//ifFileExist returned false but the file exist
|
|
CPPUNIT_ASSERT_MESSAGE( "#This file is not exist, copy failed. please manually clean-up directory and file under /tmp", ifFileExist( aDLLURL ) == sal_True );
|
|
|
|
//test if can create a normal file
|
|
::rtl::OUString aFileURL = aMyDirURL + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/test_file"));
|
|
::osl::File testFile( aFileURL );
|
|
nError = testFile.open( osl_File_OpenFlag_Create );
|
|
CPPUNIT_ASSERT_MESSAGE( "#create failed. please manually clean-up directory and file under /tmp", nError == ::osl::FileBase::E_None );
|
|
CPPUNIT_ASSERT_MESSAGE( "#This file is not exist, create failed. please manually clean-up directory and file under /tmp", ifFileExist( aFileURL ) == sal_True );
|
|
|
|
//load the copied dll
|
|
::osl::Module aMod( aDLLURL );
|
|
::osl::Module aMod1;
|
|
|
|
sal_Bool bOK = aMod1.load( aDLLURL );
|
|
bRes = oslModule(aMod) == oslModule(aMod1);
|
|
aMod.unload( );
|
|
aMod1.unload( );
|
|
deleteTestFile( aFileURL );
|
|
deleteTestFile( aDLLURL );
|
|
deleteTestDirectory( aMyDirURL );
|
|
deleteTestDirectory( aPidDirURL );
|
|
|
|
CPPUNIT_ASSERT_MESSAGE( "#test comment#: load lib which is under a CJK directory.",
|
|
sal_True == bRes && bOK == sal_True );
|
|
#endif
|
|
}
|
|
|
|
CPPUNIT_TEST_SUITE( load );
|
|
CPPUNIT_TEST( load_001 );
|
|
CPPUNIT_TEST( load_002 );
|
|
CPPUNIT_TEST_SUITE_END( );
|
|
}; // class load
|
|
|
|
|
|
/** testing the method:
|
|
void SAL_CALL unload()
|
|
*/
|
|
class unload : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
sal_Bool bRes, bRes1;
|
|
|
|
void unload_001( )
|
|
{
|
|
::osl::Module aMod( getDllURL( ) );
|
|
|
|
aMod.unload( );
|
|
bRes = oslModule(aMod) ==NULL;
|
|
|
|
CPPUNIT_ASSERT_MESSAGE( "#test comment#: unload function should do the same thing as destructor.",
|
|
sal_True == bRes );
|
|
}
|
|
|
|
CPPUNIT_TEST_SUITE( unload );
|
|
CPPUNIT_TEST( unload_001 );
|
|
CPPUNIT_TEST_SUITE_END( );
|
|
}; // class unload
|
|
|
|
|
|
/** testing the methods:
|
|
sal_Bool SAL_CALL is() const
|
|
*/
|
|
class is : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
sal_Bool bRes, bRes1;
|
|
|
|
void is_001( )
|
|
{
|
|
OUString aFileURL;
|
|
bRes = osl::Module::getUrlFromAddress( ( void* ) &::osl_Module::testClass::myFunc, aFileURL );
|
|
if ( !( bRes ) )
|
|
{
|
|
CPPUNIT_ASSERT_MESSAGE("Cannot locate current module - using executable instead", sal_False );
|
|
}
|
|
|
|
::osl::Module aMod;
|
|
bRes = aMod.is( );
|
|
aMod.load( aFileURL );
|
|
bRes1 = aMod.is( );
|
|
aMod.unload( );
|
|
|
|
CPPUNIT_ASSERT_MESSAGE( "#test comment#: test if a module is a loaded module.",
|
|
sal_False == bRes && sal_True == bRes1);
|
|
}
|
|
CPPUNIT_TEST_SUITE( is );
|
|
CPPUNIT_TEST( is_001 );
|
|
CPPUNIT_TEST_SUITE_END( );
|
|
}; // class is
|
|
|
|
|
|
/** testing the methods:
|
|
void* SAL_CALL getSymbol( const ::rtl::OUString& strSymbolName)
|
|
*/
|
|
class getSymbol : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
sal_Bool bRes;
|
|
|
|
void getSymbol_001( )
|
|
{
|
|
#if !defined( MACOSX )
|
|
// TODO: Find out why this fails on Mac OS X
|
|
::osl::Module aMod( getDllURL( ) );
|
|
FuncPtr pFunc = ( FuncPtr ) aMod.getSymbol( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("firstfunc")) );
|
|
bRes = sal_False;
|
|
if ( pFunc )
|
|
bRes = pFunc( bRes );
|
|
aMod.unload();
|
|
|
|
CPPUNIT_ASSERT_MESSAGE( "#test comment#: load a dll and call one function in it.",
|
|
sal_True == bRes );
|
|
#endif
|
|
}
|
|
|
|
CPPUNIT_TEST_SUITE( getSymbol );
|
|
CPPUNIT_TEST( getSymbol_001 );
|
|
CPPUNIT_TEST_SUITE_END( );
|
|
}; // class getSymbol
|
|
|
|
|
|
/** testing the methods:
|
|
operator oslModule() const
|
|
*/
|
|
class optr_oslModule : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
sal_Bool bRes, bRes1;
|
|
|
|
void optr_oslModule_001( )
|
|
{
|
|
#if !defined( MACOSX )
|
|
// TODO: Find out why this fails on Mac OS X
|
|
::osl::Module aMod;
|
|
bRes = ( (oslModule)aMod == NULL );
|
|
|
|
aMod.load( getDllURL( ) );
|
|
bRes1 = (oslModule)aMod != NULL;
|
|
|
|
aMod.unload( );
|
|
|
|
CPPUNIT_ASSERT_MESSAGE( "#test comment#: the m_Module of a Module instance will be NULL when is not loaded, it will not be NULL after loaded.",
|
|
sal_True == bRes && sal_True == bRes1);
|
|
#endif
|
|
}
|
|
|
|
void optr_oslModule_002( )
|
|
{
|
|
#if !defined( MACOSX )
|
|
// TODO: Find out why this fails on Mac OS X
|
|
::osl::Module aMod( getDllURL( ) );
|
|
::rtl::OUString funcName( RTL_CONSTASCII_USTRINGPARAM("firstfunc") );
|
|
|
|
FuncPtr pFunc = ( FuncPtr ) osl_getSymbol( (oslModule)aMod, funcName.pData );
|
|
bRes = sal_False;
|
|
if ( pFunc )
|
|
bRes = pFunc( bRes );
|
|
|
|
aMod.unload();
|
|
|
|
CPPUNIT_ASSERT_MESSAGE( "#test comment#: use m_Module to call osl_getSymbol() function.",
|
|
sal_True == bRes );
|
|
#endif
|
|
}
|
|
|
|
CPPUNIT_TEST_SUITE( optr_oslModule );
|
|
CPPUNIT_TEST( optr_oslModule_001 );
|
|
CPPUNIT_TEST( optr_oslModule_002 );
|
|
CPPUNIT_TEST_SUITE_END( );
|
|
}; // class optr_oslModule
|
|
|
|
/** testing the methods:
|
|
oslGenericFunction SAL_CALL getFunctionSymbol( const ::rtl::OUString& ustrFunctionSymbolName )
|
|
*/
|
|
class getFunctionSymbol : public CppUnit::TestFixture
|
|
{
|
|
public:
|
|
sal_Bool bRes, bRes1;
|
|
|
|
void getFunctionSymbol_001( )
|
|
{
|
|
#if !defined( MACOSX )
|
|
// TODO: Find out why this fails on Mac OS X
|
|
::osl::Module aMod( getDllURL( ) );
|
|
oslGenericFunction oslFunc = aMod.getFunctionSymbol( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("firstfunc")) );
|
|
::rtl::OUString aLibraryURL;
|
|
bRes = ::osl::Module::getUrlFromAddress( oslFunc, aLibraryURL);
|
|
aMod.unload();
|
|
CPPUNIT_ASSERT_MESSAGE( "#test comment#: load a dll and get its function addr and get its URL.",
|
|
sal_True == bRes && aLibraryURL.equalsIgnoreAsciiCase( getDllURL() ) );
|
|
#endif
|
|
}
|
|
|
|
CPPUNIT_TEST_SUITE( getFunctionSymbol );
|
|
CPPUNIT_TEST( getFunctionSymbol_001 );
|
|
CPPUNIT_TEST_SUITE_END( );
|
|
}; // class getFunctionSymbol
|
|
|
|
// -----------------------------------------------------------------------------
|
|
CPPUNIT_TEST_SUITE_REGISTRATION(osl_Module::ctors);
|
|
CPPUNIT_TEST_SUITE_REGISTRATION(osl_Module::getUrlFromAddress);
|
|
CPPUNIT_TEST_SUITE_REGISTRATION(osl_Module::load);
|
|
CPPUNIT_TEST_SUITE_REGISTRATION(osl_Module::unload);
|
|
CPPUNIT_TEST_SUITE_REGISTRATION(osl_Module::is);
|
|
CPPUNIT_TEST_SUITE_REGISTRATION(osl_Module::getSymbol);
|
|
CPPUNIT_TEST_SUITE_REGISTRATION(osl_Module::optr_oslModule);
|
|
CPPUNIT_TEST_SUITE_REGISTRATION(osl_Module::getFunctionSymbol);
|
|
// -----------------------------------------------------------------------------
|
|
|
|
} // namespace osl_Module
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// this macro creates an empty function, which will called by the RegisterAllFunctions()
|
|
// to let the user the possibility to also register some functions by hand.
|
|
CPPUNIT_PLUGIN_IMPLEMENT();
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|