diff options
| author | Patrick Williams <iawillia@us.ibm.com> | 2012-05-23 13:36:26 -0500 |
|---|---|---|
| committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2012-06-07 14:21:56 -0500 |
| commit | e9ac3a3dbf5277e879970c9f07f10e6f75180642 (patch) | |
| tree | 6d72ce3eaf983fcf994b531a49508ef49a609f23 /src/usr/util | |
| parent | 870a420dde20aff736d4a6e38517e9104b35ffce (diff) | |
| download | talos-hostboot-e9ac3a3dbf5277e879970c9f07f10e6f75180642.tar.gz talos-hostboot-e9ac3a3dbf5277e879970c9f07f10e6f75180642.zip | |
Port UtilStream, UtilMem, UtilFile from FSP.
Change-Id: Id17617544a8c4ed646aa8410cb968ba9376dea68
RTC: 41638
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/1097
Tested-by: Jenkins Server
Reviewed-by: Douglas R. Gilbert <dgilbert@us.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src/usr/util')
| -rw-r--r-- | src/usr/util/makefile | 2 | ||||
| -rw-r--r-- | src/usr/util/utilbase.C | 29 | ||||
| -rw-r--r-- | src/usr/util/utilbase.H | 39 | ||||
| -rw-r--r-- | src/usr/util/utilfile.C | 311 | ||||
| -rw-r--r-- | src/usr/util/utilmem.C | 435 | ||||
| -rw-r--r-- | src/usr/util/utilstream.C | 82 |
6 files changed, 897 insertions, 1 deletions
diff --git a/src/usr/util/makefile b/src/usr/util/makefile index d48edb34a..db91675be 100644 --- a/src/usr/util/makefile +++ b/src/usr/util/makefile @@ -23,7 +23,7 @@ ROOTPATH = ../../.. MODULE = util -OBJS = threadpool.o +OBJS = threadpool.o utilbase.o utilstream.o utilmem.o utilfile.o SUBDIRS = test.d diff --git a/src/usr/util/utilbase.C b/src/usr/util/utilbase.C new file mode 100644 index 000000000..a510e4407 --- /dev/null +++ b/src/usr/util/utilbase.C @@ -0,0 +1,29 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/util/utilbase.C $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END +#include "utilbase.H" + +namespace Util +{ + trace_desc_t* g_util_trace; + TRAC_INIT(&g_util_trace, "UTIL", 4096); +}; diff --git a/src/usr/util/utilbase.H b/src/usr/util/utilbase.H new file mode 100644 index 000000000..bca7cf2b3 --- /dev/null +++ b/src/usr/util/utilbase.H @@ -0,0 +1,39 @@ +// IBM_PROLOG_BEGIN_TAG +// This is an automatically generated prolog. +// +// $Source: src/usr/util/utilbase.H $ +// +// IBM CONFIDENTIAL +// +// COPYRIGHT International Business Machines Corp. 2012 +// +// p1 +// +// Object Code Only (OCO) source materials +// Licensed Internal Code Source Materials +// IBM HostBoot Licensed Internal Code +// +// The source code for this program is not published or other- +// wise divested of its trade secrets, irrespective of what has +// been deposited with the U.S. Copyright Office. +// +// Origin: 30 +// +// IBM_PROLOG_END + +#ifndef __UTIL_UTILBASE_H +#define __UTIL_UTILBASE_H + +#include <trace/interface.H> + +namespace Util +{ + extern trace_desc_t* g_util_trace; +}; + +#define UTIL_DT(...) TRACDCOMP( Util::g_util_trace, __VA_ARGS__ ) +#define UTIL_FT(...) TRACFCOMP( Util::g_util_trace, __VA_ARGS__ ) + +#define UTIL_BOOL_ALPHA(x) ((x) ? "TRUE" : "FALSE") + +#endif diff --git a/src/usr/util/utilfile.C b/src/usr/util/utilfile.C new file mode 100644 index 000000000..52c63420f --- /dev/null +++ b/src/usr/util/utilfile.C @@ -0,0 +1,311 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/util/utilfile.C $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2003-2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +/** + * @file utilfile.C + * + * @brief Stream manipulation + * + * Used for creating and manipulating streams + */ + +/*****************************************************************************/ +// I n c l u d e s +/*****************************************************************************/ + +#include <util/utilfile.H> +#include <util/utilmem.H> +#include <errl/errlentry.H> +#include <vfs/vfs.H> + +#include "utilbase.H" + +using namespace Util; +using namespace ERRORLOG; + +static const char UTIL_FILE_INVALID_NM[] = ""; + +/*****************************************************************************/ +// Default Constructor +/*****************************************************************************/ +UtilFile::UtilFile() +: iv_filePathName(NULL), iv_contents() +{ + UTIL_DT("UtilFile: Default Constructor, no filename yet"); + FileName(UTIL_FILE_INVALID_NM); +} + + +/*****************************************************************************/ +// Constructor +/*****************************************************************************/ +UtilFile::UtilFile(const char * i_filePathName) +: iv_filePathName(NULL), iv_contents() +{ + UTIL_DT("UtilFile: File name constructor invoked"); + FileName(i_filePathName); +} + + +/*****************************************************************************/ +// Destructor +/*****************************************************************************/ +UtilFile::~UtilFile() +{ + UTIL_DT("UtilFile: Destructor invoked on file: %s",iv_filePathName); + + // Eliminate prior errors + // - this is done bcs close will abort if there are prior errors + delete getLastError(); + + // Close it up: only if it was created by us + if ( strcmp( iv_filePathName, UTIL_FILE_INVALID_NM ) != 0 ) + { + Close(); + } + + + delete[] iv_filePathName; + + // Note: a lingering iv_lastError will be trashed + // by the base destructor + +} + + +/*****************************************************************************/ +// Does the file exist? +/*****************************************************************************/ +bool UtilFile::exists( void ) const +{ + return VFS::module_exists(iv_filePathName); +} + +/*****************************************************************************/ +// Does the file exist? +/*****************************************************************************/ +bool UtilFile::exists( const char *i_fileName ) +{ + return VFS::module_exists(i_fileName); +} + +/*****************************************************************************/ +// Open the file opening the file in flash by default. +/*****************************************************************************/ +void UtilFile::Open( + const char * i_mode + ) +{ + do + { + if (iv_lastError) + { + UTIL_FT("E> UtilFile: Stream Operations Suspended on %s", + iv_filePathName); + break; + } + + // Load module. + iv_lastError = VFS::module_load(iv_filePathName); + if (iv_lastError) + { + break; + } + + // Get module address / size. + const char* l_address = NULL; + size_t l_size = 0; + + iv_lastError = VFS::module_address(iv_filePathName, l_address, l_size); + if (iv_lastError) + { + break; + } + + // Create UtilMem object to overlay module location in memory. + iv_contents = UtilMem(const_cast<char*>(l_address), l_size); + + iv_eof = iv_contents.eof(); + iv_lastError = iv_contents.getLastError(); + + } while(0); +} + +/*****************************************************************************/ +// Open the file +/*****************************************************************************/ +void UtilFile::Open( + const char * i_file, + const char * i_mode +) +{ + do + { + if (iv_lastError) + { + UTIL_FT("E> UtilFile: Stream Operations Suspended on %s", + iv_filePathName); + break; + } + + if (isOpen()) + { + Close(); + } + if (iv_lastError) + { + break; + } + + FileName(i_file); + Open(i_mode); + + } while(0); +} + + +/*****************************************************************************/ +// Close the file +/*****************************************************************************/ +void UtilFile::Close() +{ + do + { + + if ( iv_lastError ) + { + UTIL_FT("E> UtilFile: Stream operations suspended on %s", + iv_filePathName); + break; + } + + if (!isOpen()) + { + UTIL_DT("E> UtilFile: %s not open", iv_filePathName); + break; + } + + // Reset underlying UtilMem. + iv_contents = UtilMem(); + iv_eof = iv_contents.eof(); + + // Unload module. + iv_lastError = VFS::module_unload(iv_filePathName); + + } while(0); + +} + + +/*****************************************************************************/ +// Read the file +/*****************************************************************************/ +uint32_t UtilFile::read( + void * o_buffer, + uint32_t i_size + ) +{ + size_t l_rc = 0; + + do + { + if (iv_lastError) + { + UTIL_FT("E> UtilFile: Stream operations suspended on %s", + iv_filePathName); + break; + } + + l_rc = iv_contents.read(o_buffer, i_size); + + iv_eof = iv_contents.eof(); + iv_lastError = iv_contents.getLastError(); + + } while(0); + + return l_rc; +} + +/*****************************************************************************/ +// Write the file +/*****************************************************************************/ +uint32_t UtilFile::write( + const void *i_buffer, + uint32_t i_size + ) +{ + assert(false, "E> UtilFile: Write attempted in Hostboot on %s", + iv_filePathName); + return 0; +} + +/*****************************************************************************/ +// Seek the file +/*****************************************************************************/ +uint32_t UtilFile::seek( + int i_pos, + whence i_whence + ) +{ + uint32_t l_rc = 0; + + do + { + if (iv_lastError) + { + UTIL_FT("E> UtilFile: Stream operations suspended on %s", + iv_filePathName); + break; + } + + l_rc = iv_contents.seek(i_pos, i_whence); + + iv_eof = iv_contents.eof(); + iv_lastError = iv_contents.getLastError(); + + } while(0); + + return l_rc; +} + +/*****************************************************************************/ +// Query the file size +/*****************************************************************************/ +uint32_t UtilFile::size() const +{ + return iv_contents.size(); +} + +/*****************************************************************************/ +// Set/Get the object's filename +/*****************************************************************************/ +void UtilFile::FileName( const char * i_name ) +{ + // Cleanup + delete[] iv_filePathName; + + iv_filePathName = new char[strlen(i_name) + 1]; + + strcpy(iv_filePathName, i_name); +} + diff --git a/src/usr/util/utilmem.C b/src/usr/util/utilmem.C new file mode 100644 index 000000000..0b78a53c4 --- /dev/null +++ b/src/usr/util/utilmem.C @@ -0,0 +1,435 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/util/utilmem.C $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2003-2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +/** + * @file utilmem.C + * + * @brief Stream manipulation + * + * Used for creating and manipulating streams + */ + +/*****************************************************************************/ +// I n c l u d e s +/*****************************************************************************/ + +#include <sys/task.h> +#include <util/utilmem.H> +#include <util/utilfile.H> +#include <util/util_reasoncodes.H> +#include <errl/errlentry.H> + +#include "utilbase.H" + +using namespace Util; +using namespace ERRORLOG; + +/*****************************************************************************/ +// Default Constructor +/*****************************************************************************/ +UtilMem::UtilMem() +: iv_memStart( 0 ), iv_offset( 0 ), iv_size( 0 ), iv_autoGrow( true ), + iv_autoCleanup( true ) +{ + UTIL_DT("I> UtilMem: Default Constructor, no memory"); +} + +/*****************************************************************************/ +// Constructor with Size parameter +/*****************************************************************************/ +UtilMem::UtilMem(uint32_t i_size) +: iv_memStart( 0 ), iv_offset( 0 ), iv_size( i_size ), iv_autoGrow( false ), + iv_autoCleanup( true ) +{ + UTIL_DT("I> UtilMem: Memory size constructor: %i, p=%p", + i_size,iv_memStart); + iv_memStart = static_cast<uint8_t *>(malloc(i_size)); + reset(0); +} + +/*****************************************************************************/ +// Constructor with Buffer and Size parameters +/*****************************************************************************/ +UtilMem::UtilMem(void * i_buffer, uint32_t i_size) +: iv_memStart(static_cast<uint8_t*>(i_buffer)), iv_offset( 0 ), + iv_size( i_size ), iv_autoGrow( false ), iv_autoCleanup( false ) +{ + UTIL_DT("I> UtilMem: Foreign buffer constructor: %i, p=%p", + i_size,i_buffer); +} + + +/*****************************************************************************/ +// Assignment operator +/*****************************************************************************/ +UtilMem & UtilMem::operator = ( const UtilMem & i_right ) +{ + if ( &i_right != this ) + { + // Base assignment + UtilStream::operator=( i_right ); + + // Cleanup + if ( iv_autoCleanup ) + { + free(iv_memStart); + } + + // Setup + iv_offset = i_right.iv_offset; + iv_size = i_right.iv_size; + iv_autoGrow = i_right.iv_autoGrow; + iv_autoCleanup = i_right.iv_autoCleanup; + + if ( i_right.iv_autoCleanup ) + { + iv_memStart = static_cast<uint8_t*>(malloc( i_right.iv_size )); + memcpy(iv_memStart,i_right.iv_memStart,iv_size); + } + else + { + UTIL_FT("W> UtilMem: Assignment results in 2 Interfaces to " + "1 buffer, p=%p", i_right.iv_memStart); + iv_memStart = i_right.iv_memStart; + } + + + // Trace + UTIL_DT("I> UtilMem: dst=%p,offset=%i,size=%i,autogrow=%s,autoclean=%s", + iv_memStart,iv_offset,iv_size,UTIL_BOOL_ALPHA(iv_autoGrow), + UTIL_BOOL_ALPHA(iv_autoCleanup)); + + } + + return *this; + +} + +/*****************************************************************************/ +// UtilFile assignment +/*****************************************************************************/ +UtilMem & UtilMem::operator = ( UtilFile & i_right ) +{ + UtilFile & l_file = i_right; + + l_file.read( iv_memStart, iv_size ); + + return *this; +} + + +/*****************************************************************************/ +// Destructor +/*****************************************************************************/ +UtilMem::~UtilMem() +{ + UTIL_DT("I> UtilMem: Destructor: p=%p,size=%i,autoclean=%s", + iv_memStart,iv_size,UTIL_BOOL_ALPHA(iv_autoCleanup)); + + if (iv_autoCleanup) + { + free(iv_memStart); + iv_memStart = 0; + } +} + +/*****************************************************************************/ +// Read the file +/*****************************************************************************/ +uint32_t UtilMem::read( + void * o_buffer, + uint32_t i_size + ) +{ + ReasonCode l_erc = UTIL_ERC_NONE; + uint32_t l_rc = 0; + + if ( ! iv_memStart ) // Invalid pointer + { + UTIL_FT("E> UtilMem: Bad memory receive pointer, can't read"); + + /*@ + * @errortype + * @moduleid UTIL::MOD_MEM_READ + * @reasoncode UTIL::UTIL_ERC_BAD_PTR + * @userdata1[0:31] Task ID. + * @userdata1[31:64] End of File (boolean) + * @userdata2 Address of memory buffer. + * @devdesc Bad memory pointer recieved. + */ + l_erc = UTIL_ERC_BAD_PTR; + } + else if ( iv_eof ) // Not at EOF + { + UTIL_FT("E> UtilMem: Stream is at end of file"); + + /*@ + * @errortype + * @moduleid UTIL::MOD_MEM_READ + * @reasoncode UTIL::UTIL_ERC_EOF + * @userdata1[0:31] Task ID. + * @userdata1[31:64] End of File (boolean) + * @userdata2 Address of memory buffer. + * @devdesc End of file reached. + */ + l_erc = UTIL_ERC_EOF; + } + else if ( i_size && ! iv_lastError ) // Size > 0 && no errors + { + l_rc = i_size; + + if ( ( iv_offset + i_size ) > iv_size ) + { + // Recalculate i_size + l_rc = iv_size - iv_offset; + + // Set EOF + iv_eof = true; + l_erc = UTIL_ERC_EOF; + } + + // Copy memory + memcpy( o_buffer, (iv_memStart + iv_offset), l_rc ); + + // Set the new current position + iv_offset += l_rc; + + } + + + if ( iv_lastError == 0 && l_erc != UTIL_ERC_NONE ) + { + UTIL_FT("E> UtilMem: Read Failed, Buffer 0x%p, Offset 0x%X, Size 0x%X, " + "Error Code 0x%X", + iv_memStart, iv_offset, i_size, l_erc); + + iv_lastError = new ErrlEntry( + ERRL_SEV_UNRECOVERABLE, + UTIL_MOD_MEM_READ, + l_erc, + TWO_UINT32_TO_UINT64(task_gettid(), iv_eof), + reinterpret_cast<uint64_t>(iv_memStart) + ); + + // collect some trace by default + iv_lastError->collectTrace( UTIL_COMP_NAME ); + + } + else if ( iv_lastError ) + { + UTIL_FT("E> UtilMem: Suspended on %p due to %x - %x", + iv_memStart,iv_lastError->reasonCode(), + iv_lastError->moduleId()); + } + + return l_rc; +} + + +/*****************************************************************************/ +// Write the file +/*****************************************************************************/ +uint32_t UtilMem::write( + const void *i_buffer, + uint32_t i_size + ) +{ + ReasonCode l_erc = UTIL_ERC_NONE; + uint32_t l_rc = 0; + + + if ( ! iv_memStart && ! iv_autoGrow ) // Invalid pointer + { + UTIL_FT("E> UtilMem: Bad memory receive pointer, can't write"); + + /*@ + * @errortype + * @moduleid UTIL::MOD_MEM_WRITE + * @reasoncode UTIL::UTIL_ERC_BAD_PTR + * @userdata1[0:31] Task ID. + * @userdata1[31:64] End of File (boolean) + * @userdata2 Address of memory buffer. + * @devdesc Bad memory pointer recieved. + */ + l_erc = UTIL_ERC_BAD_PTR; + } + else if ( iv_eof && ! iv_autoGrow ) // Not at EOF + { + UTIL_FT("E> UtilMem: Stream is at end of file"); + + /*@ + * @errortype + * @moduleid UTIL::MOD_MEM_WRITE + * @reasoncode UTIL::UTIL_ERC_EOF + * @userdata1[0:31] Task ID. + * @userdata1[31:64] End of File (boolean) + * @userdata2 Address of memory buffer. + * @devdesc End of file reached. + */ + l_erc = UTIL_ERC_EOF; + } + else if ( i_size && ! iv_lastError ) // Size > 0 && no errors + { + l_rc = i_size; + + if ( ( iv_offset + i_size ) > iv_size ) + { + if (iv_autoGrow) + { + iv_size = iv_offset + i_size; + iv_memStart = + static_cast<uint8_t *>(realloc( iv_memStart, iv_size )); + } + else + { + // Recalculate i_size + l_rc = iv_size - iv_offset; + + // Set EOF + iv_eof = true; + l_erc = UTIL_ERC_EOF; + } + } + + // Copy memory + memcpy((iv_memStart + iv_offset), i_buffer, l_rc); + + // Set the new current position + iv_offset += l_rc; + + } + + + if ( iv_lastError == 0 && l_erc != UTIL_ERC_NONE ) + { + UTIL_FT("E> UtilMem: Write Failed, Buffer 0x%p, Offset 0x%X, " + "Size 0x%X, Error Code 0x%X", + iv_memStart, iv_offset, i_size, l_erc); + + // Create an Error Log + iv_lastError = new ErrlEntry( + ERRL_SEV_UNRECOVERABLE, + UTIL_MOD_MEM_WRITE, + l_erc, + TWO_UINT32_TO_UINT64(task_gettid(), iv_eof), + reinterpret_cast<uint64_t>(iv_memStart) + ); + + // collect some trace by default + iv_lastError->collectTrace( UTIL_COMP_NAME ); + + } + else if (iv_lastError) + { + UTIL_FT("E> UtilMem: Suspended on %p due to %x - %x", + iv_memStart,iv_lastError->reasonCode(), + iv_lastError->moduleId()); + } + + return l_rc; + +} + +/*****************************************************************************/ +// Seek the file +/*****************************************************************************/ +uint32_t UtilMem::seek( + int i_pos, + whence i_whence + ) +{ + ssize_t l_offset = 0; + uint32_t l_origin = 0; + + if (!iv_lastError) + { + if ( i_whence == START ) + { + // Set the origin + l_origin = 0; + } + else if (i_whence == CURRENT) + { + // Set the current position + l_origin = iv_offset; + } + else if ( i_whence == END ) + { + l_origin = iv_size; + } + + l_offset = l_origin + i_pos; + + if (l_offset < 0) + { + // Set the offset to the beginning + iv_offset = 0; + } + else if (l_offset > iv_size) + { + iv_offset = iv_size - 1; + } + else + { + iv_offset = l_offset; + } + + // Clear the EOF indicator + iv_eof = false; + } + else + { + UTIL_FT("E> UtilMem: Suspended on %p due to %x - %x", + iv_memStart,iv_lastError->reasonCode(), + iv_lastError->moduleId()); + } + + return iv_offset; +} + +/*****************************************************************************/ +// Change size +/*****************************************************************************/ +void UtilMem::changeSize( uint32_t i_size ) +{ + if ( iv_autoCleanup ) + { + iv_offset = 0; + iv_size = i_size; + iv_memStart = static_cast<uint8_t*>(realloc( iv_memStart, iv_size )); + } +} + + + +/*****************************************************************************/ +// Reset the object +/*****************************************************************************/ +void UtilMem::reset( int i_c ) +{ + memset( iv_memStart, i_c, iv_size ); + iv_offset = 0; + iv_eof = 0; + delete getLastError(); +} + diff --git a/src/usr/util/utilstream.C b/src/usr/util/utilstream.C new file mode 100644 index 000000000..69a5fe1e0 --- /dev/null +++ b/src/usr/util/utilstream.C @@ -0,0 +1,82 @@ +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/util/utilstream.C $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2003-2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ +/** + * @file utilstream.C + * + * @brief Stream manipulation + * + * Used for creating and manipulating streams +*/ + +/*****************************************************************************/ +// I n c l u d e s +/*****************************************************************************/ +#include <util/utilstream.H> + + +/*****************************************************************************/ +// Default Constructor +/*****************************************************************************/ +UtilStream::UtilStream() +: iv_eof( false ), iv_lastError( 0 ) +{ +} + + +/*****************************************************************************/ +// Assignment operator +/*****************************************************************************/ +UtilStream & UtilStream::operator= ( const UtilStream & i_right ) +{ + if ( &i_right != this ) + { + delete iv_lastError; + + iv_eof = false; + iv_lastError = 0; + + } + + return *this; +} + + +/*****************************************************************************/ +// Default destructor +/*****************************************************************************/ +UtilStream::~UtilStream() +{ + delete iv_lastError; +} + + +/*****************************************************************************/ +// Set the last Error Log +/*****************************************************************************/ +void UtilStream::setLastError( errlHndl_t i_error ) +{ + delete iv_lastError; + iv_lastError = i_error; +} + |

