| //===-- MIUtilString.cpp ----------------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| //++ |
| // File: MIUtilString.h |
| // |
| // Overview: CMIUtilString implementation. |
| // |
| // Environment: Compilers: Visual C++ 12. |
| // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 |
| // Libraries: See MIReadmetxt. |
| // |
| // Copyright: None. |
| //-- |
| |
| // Third party headers |
| #include <memory> // std::unique_ptr |
| #include <stdarg.h> // va_list, va_start, var_end |
| #include <sstream> // std::stringstream |
| #include <string.h> // for strcpy |
| #include <limits.h> // for ULONG_MAX |
| |
| // In-house headers: |
| #include "MIUtilString.h" |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: CMIUtilString constructor. |
| // Type: Method. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| CMIUtilString::CMIUtilString( void ) |
| : std::string() |
| { |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: CMIUtilString constructor. |
| // Type: Method. |
| // Args: vpData - Pointer to UTF8 text data. |
| // Return: None. |
| // Throws: None. |
| //-- |
| CMIUtilString::CMIUtilString( const MIchar * vpData ) |
| : std::string( vpData ) |
| { |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: CMIUtilString constructor. |
| // Type: Method. |
| // Args: vpData - Pointer to UTF8 text data. |
| // Return: None. |
| // Throws: None. |
| //-- |
| CMIUtilString::CMIUtilString( const MIchar * const * vpData ) |
| : std::string( (const char *) vpData ) |
| { |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: CMIUtilString assigment operator. |
| // Type: Method. |
| // Args: vpRhs - Pointer to UTF8 text data. |
| // Return: CMIUtilString & - *this string. |
| // Throws: None. |
| //-- |
| CMIUtilString & CMIUtilString::operator= ( const MIchar * vpRhs ) |
| { |
| if( *this == vpRhs ) |
| return *this; |
| |
| if( vpRhs != nullptr ) |
| { |
| assign( vpRhs ); |
| } |
| |
| return *this; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: CMIUtilString assigment operator. |
| // Type: Method. |
| // Args: vrRhs - The other string to copy from. |
| // Return: CMIUtilString & - *this string. |
| // Throws: None. |
| //-- |
| CMIUtilString & CMIUtilString::operator= ( const std::string & vrRhs ) |
| { |
| if( *this == vrRhs ) |
| return *this; |
| |
| assign( vrRhs ); |
| |
| return *this; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: CMIUtilString destructor. |
| // Type: Method. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| CMIUtilString::~CMIUtilString( void ) |
| { |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Perform a snprintf format style on a string data. A new string object is |
| // created and returned. |
| // Type: Static method. |
| // Args: vrFormat - (R) Format string data instruction. |
| // vArgs - (R) Var list args of any type. |
| // Return: CMIUtilString - Number of splits found in the string data. |
| // Throws: None. |
| //-- |
| CMIUtilString CMIUtilString::FormatPriv( const CMIUtilString & vrFormat, va_list vArgs ) |
| { |
| CMIUtilString strResult; |
| MIint nFinal = 0; |
| MIint n = vrFormat.size(); |
| |
| // IOR: mysterious crash in this function on some windows builds not able to duplicate |
| // but found article which may be related. Crash occurs in vsnprintf() or va_copy() |
| // Duplicate vArgs va_list argument pointer to ensure that it can be safely used in |
| // a new frame |
| // http://julipedia.meroh.net/2011/09/using-vacopy-to-safely-pass-ap.html |
| va_list argsDup; |
| va_copy( argsDup, vArgs ); |
| |
| // Create a copy va_list to reset when we spin |
| va_list argsCpy; |
| va_copy( argsCpy, argsDup ); |
| |
| if( n == 0 ) |
| return strResult; |
| |
| n = n << 4; // Reserve 16 times as much the length of the vrFormat |
| |
| std::unique_ptr< char[] > pFormatted; |
| while( 1 ) |
| { |
| pFormatted.reset( new char[ n + 1 ] ); // +1 for safety margin |
| ::strncpy( &pFormatted[ 0 ], vrFormat.c_str(), n ); |
| |
| // We need to restore the variable argument list pointer to the start again |
| // before running vsnprintf() more then once |
| va_copy( argsDup, argsCpy ); |
| |
| nFinal = ::vsnprintf( &pFormatted[ 0 ], n, vrFormat.c_str(), argsDup ); |
| if( (nFinal < 0) || (nFinal >= n) ) |
| n += abs( nFinal - n + 1 ); |
| else |
| break; |
| } |
| |
| va_end( argsCpy ); |
| va_end( argsDup ); |
| |
| strResult = pFormatted.get(); |
| |
| return strResult; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Perform a snprintf format style on a string data. A new string object is |
| // created and returned. |
| // Type: Static method. |
| // Args: vrFormat - (R) Format string data instruction. |
| // ... - (R) Var list args of any type. |
| // Return: CMIUtilString - Number of splits found in the string data. |
| // Throws: None. |
| //-- |
| CMIUtilString CMIUtilString::Format( const CMIUtilString & vrFormating, ... ) |
| { |
| va_list args; |
| va_start( args, vrFormating ); |
| CMIUtilString strResult = CMIUtilString::FormatPriv( vrFormating, args ); |
| va_end( args ); |
| |
| return strResult; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Perform a snprintf format style on a string data. A new string object is |
| // created and returned. |
| // Type: Static method. |
| // Args: vrFormat - (R) Format string data instruction. |
| // vArgs - (R) Var list args of any type. |
| // Return: CMIUtilString - Number of splits found in the string data. |
| // Throws: None. |
| //-- |
| CMIUtilString CMIUtilString::FormatValist( const CMIUtilString & vrFormating, va_list vArgs ) |
| { |
| return CMIUtilString::FormatPriv( vrFormating, vArgs ); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Splits string into array of strings using delimiter. If multiple delimiter |
| // are found in sequence then they are not added to the list of splits. |
| // Type: Method. |
| // Args: vData - (R) String data to be split up. |
| // vDelimiter - (R) Delimiter char or text. |
| // vwVecSplits - (W) Container of splits found in string data. |
| // Return: MIuint - Number of splits found in the string data. |
| // Throws: None. |
| //-- |
| MIuint CMIUtilString::Split( const CMIUtilString & vDelimiter, VecString_t & vwVecSplits ) const |
| { |
| vwVecSplits.clear(); |
| |
| if( this->empty() || vDelimiter.empty() ) |
| return 0; |
| |
| MIint nPos = find( vDelimiter ); |
| if( nPos == (MIint) std::string::npos ) |
| { |
| vwVecSplits.push_back( *this ); |
| return 1; |
| } |
| const MIint strLen( length() ); |
| if( nPos == strLen ) |
| { |
| vwVecSplits.push_back( *this ); |
| return 1; |
| } |
| |
| MIuint nAdd1( 1 ); |
| if( (nPos > 0) && (substr( 0, nPos ) != vDelimiter) ) |
| { |
| nPos = 0; |
| nAdd1 = 0; |
| } |
| MIint nPos2 = find( vDelimiter, nPos + 1 ); |
| while( nPos2 != (MIint) std::string::npos ) |
| { |
| const MIuint len( nPos2 - nPos - nAdd1 ); |
| const std::string strSection( substr( nPos + nAdd1, len ) ); |
| if( strSection != vDelimiter ) |
| vwVecSplits.push_back( strSection.c_str() ); |
| nPos += len + 1; |
| nPos2 = find( vDelimiter, nPos + 1 ); |
| nAdd1 = 0; |
| } |
| const std::string strSection( substr( nPos, strLen - nPos ) ); |
| if( (strSection.length() != 0) && (strSection != vDelimiter) ) |
| vwVecSplits.push_back( strSection.c_str() ); |
| |
| return vwVecSplits.size(); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Splits string into array of strings using delimiter. However the string is |
| // also considered for text surrounded by quotes. Text with quotes including the |
| // delimiter is treated as a whole. If multiple delimiter are found in sequence |
| // then they are not added to the list of splits. |
| // Type: Method. |
| // Args: vData - (R) String data to be split up. |
| // vDelimiter - (R) Delimiter char or text. |
| // vwVecSplits - (W) Container of splits found in string data. |
| // Return: MIuint - Number of splits found in the string data. |
| // Throws: None. |
| //-- |
| MIuint CMIUtilString::SplitConsiderQuotes( const CMIUtilString & vDelimiter, VecString_t & vwVecSplits ) const |
| { |
| vwVecSplits.clear(); |
| |
| if( this->empty() || vDelimiter.empty() ) |
| return 0; |
| |
| MIint nPos = find( vDelimiter ); |
| if( nPos == (MIint) std::string::npos ) |
| { |
| vwVecSplits.push_back( *this ); |
| return 1; |
| } |
| const MIint strLen( length() ); |
| if( nPos == strLen ) |
| { |
| vwVecSplits.push_back( *this ); |
| return 1; |
| } |
| |
| // Look for more quotes |
| bool bHaveQuotes = false; |
| const MIchar cQuote = '"'; |
| MIint nPosQ = find( cQuote ); |
| MIint nPosQ2 = (MIint) std::string::npos; |
| if( nPosQ != (MIint) std::string::npos ) |
| { |
| nPosQ2 = find( cQuote, nPosQ + 1 ); |
| bHaveQuotes = (nPosQ2 != (MIint) std::string::npos); |
| } |
| |
| MIuint nAdd1( 1 ); |
| if( (nPos > 0) && (substr( 0, nPos ) != vDelimiter) ) |
| { |
| nPos = 0; |
| nAdd1 = 0; |
| } |
| MIint nPos2 = find( vDelimiter, nPos + 1 ); |
| while( nPos2 != (MIint) std::string::npos ) |
| { |
| if( !bHaveQuotes || (bHaveQuotes && ((nPos2 > nPosQ2) || (nPos2 < nPosQ))) ) |
| { |
| // Extract text or quoted text |
| const MIuint len( nPos2 - nPos - nAdd1 ); |
| const std::string strSection( substr( nPos + nAdd1, len ) ); |
| if( strSection != vDelimiter ) |
| vwVecSplits.push_back( strSection.c_str() ); |
| nPos += len + 1; |
| nPos2 = find( vDelimiter, nPos + 1 ); |
| nAdd1 = 0; |
| |
| if( bHaveQuotes && (nPos2 > nPosQ2) ) |
| { |
| // Reset, look for more quotes |
| bHaveQuotes = false; |
| nPosQ = find( cQuote, nPos ); |
| nPosQ2 = (MIint) std::string::npos; |
| if( nPosQ != (MIint) std::string::npos ) |
| { |
| nPosQ2 = find( cQuote, nPosQ + 1 ); |
| bHaveQuotes = (nPosQ2 != (MIint) std::string::npos); |
| } |
| } |
| } |
| else |
| { |
| // Skip passed text in quotes |
| nPos2 = find( vDelimiter, nPosQ2 + 1 ); |
| } |
| } |
| const std::string strSection( substr( nPos, strLen - nPos ) ); |
| if( (strSection.length() != 0) && (strSection != vDelimiter) ) |
| vwVecSplits.push_back( strSection.c_str() ); |
| |
| return vwVecSplits.size(); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Remove '\n' from the end of string if found. It does not alter |
| // *this string. |
| // Type: Method. |
| // Args: None. |
| // Return: CMIUtilString - New version of the string. |
| // Throws: None. |
| //-- |
| CMIUtilString CMIUtilString::StripCREndOfLine( void ) const |
| { |
| const MIint nPos = rfind( '\n' ); |
| if( nPos == (MIint) std::string::npos ) |
| return *this; |
| |
| const CMIUtilString strNew( substr( 0, nPos ).c_str() ); |
| |
| return strNew; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Remove all '\n' from the string and replace with a space. It does not alter |
| // *this string. |
| // Type: Method. |
| // Args: None. |
| // Return: CMIUtilString - New version of the string. |
| // Throws: None. |
| //-- |
| CMIUtilString CMIUtilString::StripCRAll( void ) const |
| { |
| return FindAndReplace( "\n", " " ); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Find and replace all matches of a sub string with another string. It does not |
| // alter *this string. |
| // Type: Method. |
| // Args: vFind - (R) The string to look for. |
| // vReplaceWith - (R) The string to replace the vFind match. |
| // Return: CMIUtilString - New version of the string. |
| // Throws: None. |
| //-- |
| CMIUtilString CMIUtilString::FindAndReplace( const CMIUtilString & vFind, const CMIUtilString & vReplaceWith ) const |
| { |
| if( vFind.empty() || this->empty() ) |
| return *this; |
| |
| MIint nPos = find( vFind ); |
| if( nPos == (MIint) std::string::npos ) |
| return *this; |
| |
| CMIUtilString strNew( *this ); |
| while( nPos != (MIint) std::string::npos ) |
| { |
| strNew.replace( nPos, vFind.length(), vReplaceWith ); |
| nPos += vReplaceWith.length(); |
| nPos = strNew.find( vFind, nPos ); |
| } |
| |
| return strNew; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Check if *this string is a decimal number. |
| // Type: Method. |
| // Args: None. |
| // Return: bool - True = yes number, false not a number. |
| // Throws: None. |
| //-- |
| bool CMIUtilString::IsNumber( void ) const |
| { |
| if( empty() ) |
| return false; |
| |
| if( (at( 0 ) == '-') && (length() == 1) ) |
| return false; |
| |
| const MIint nPos = find_first_not_of( "-.0123456789" ); |
| if( nPos != (MIint) std::string::npos ) |
| return false; |
| |
| return true; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Extract the number from the string. The number can be either a hexadecimal or |
| // natural number. It cannot contain other non-numeric characters. |
| // Type: Method. |
| // Args: vwrNumber - (W) Number exracted from the string. |
| // Return: bool - True = yes number, false not a number. |
| // Throws: None. |
| //-- |
| bool CMIUtilString::ExtractNumber( MIint64 & vwrNumber ) const |
| { |
| vwrNumber = 0; |
| |
| if( !IsNumber() ) |
| { |
| if( ExtractNumberFromHexadecimal( vwrNumber ) ) |
| return true; |
| |
| return false; |
| } |
| |
| std::stringstream ss( const_cast< CMIUtilString & >( *this ) ); |
| ss >> vwrNumber; |
| |
| return true; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Extract the number from the hexadecimal string.. |
| // Type: Method. |
| // Args: vwrNumber - (W) Number exracted from the string. |
| // Return: bool - True = yes number, false not a number. |
| // Throws: None. |
| //-- |
| bool CMIUtilString::ExtractNumberFromHexadecimal( MIint64 & vwrNumber ) const |
| { |
| vwrNumber = 0; |
| |
| const MIint nPos = find_first_not_of( "x01234567890ABCDEFabcedf" ); |
| if( nPos != (MIint) std::string::npos ) |
| return false; |
| |
| const MIint64 nNum = ::strtoul( this->c_str(), nullptr, 16 ); |
| if( nNum != ULONG_MAX ) |
| { |
| vwrNumber = nNum; |
| return true; |
| } |
| |
| return true; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Determine if the text is all valid alpha numeric characters. Letters can be |
| // either upper or lower case. |
| // Type: Static method. |
| // Args: vrText - (R) The text data to examine. |
| // Return: bool - True = yes all alpha, false = one or more chars is non alpha. |
| // Throws: None. |
| //-- |
| bool CMIUtilString::IsAllValidAlphaAndNumeric( const MIchar & vrText ) |
| { |
| const MIuint len = ::strlen( &vrText ); |
| if( len == 0 ) |
| return false; |
| |
| MIchar * pPtr = const_cast< MIchar * >( &vrText ); |
| for( MIuint i = 0; i < len; i++, pPtr++ ) |
| { |
| const MIchar c = *pPtr; |
| if( ::isalnum( (int) c ) == 0 ) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Check if two strings share equal contents. |
| // Type: Method. |
| // Args: vrLhs - (R) String A. |
| // vrRhs - (R) String B. |
| // Return: bool - True = yes equal, false - different. |
| // Throws: None. |
| //-- |
| bool CMIUtilString::Compare( const CMIUtilString & vrLhs, const CMIUtilString & vrRhs ) |
| { |
| // Check the sizes match |
| if( vrLhs.size() != vrRhs.size() ) |
| return false; |
| |
| return (::strncmp( vrLhs.c_str(), vrRhs.c_str(), vrLhs.size() ) == 0); |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Remove from either end of *this string the following: " \t\n\v\f\r". |
| // Type: Method. |
| // Args: None. |
| // Return: CMIUtilString - Trimmed string. |
| // Throws: None. |
| //-- |
| CMIUtilString CMIUtilString::Trim( void ) const |
| { |
| CMIUtilString strNew( *this ); |
| const MIchar * pWhiteSpace = " \t\n\v\f\r"; |
| const MIint nPos = find_last_not_of( pWhiteSpace ); |
| if( nPos != (MIint) std::string::npos ) |
| { |
| strNew = substr( 0, nPos + 1 ).c_str(); |
| } |
| const MIint nPos2 = strNew.find_first_not_of( pWhiteSpace ); |
| if( nPos2 != (MIint) std::string::npos ) |
| { |
| strNew = strNew.substr( nPos2 ).c_str(); |
| } |
| |
| return strNew; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Remove from either end of *this string the specified character. |
| // Type: Method. |
| // Args: None. |
| // Return: CMIUtilString - Trimmed string. |
| // Throws: None. |
| //-- |
| CMIUtilString CMIUtilString::Trim( const MIchar vChar ) const |
| { |
| CMIUtilString strNew( *this ); |
| const MIuint nLen = strNew.length(); |
| if( nLen > 1 ) |
| { |
| if( (strNew[ 0 ] == vChar) && (strNew[ nLen - 1 ] == vChar) ) |
| strNew = strNew.substr( 1, nLen - 2 ).c_str(); |
| } |
| |
| return strNew; |
| } |
| |
| //++ ------------------------------------------------------------------------------------ |
| // Details: Do a printf equivalent for printing a number in binary i.e. "b%llB". |
| // Type: Static method. |
| // Args: vnDecimal - (R) The number to represent in binary. |
| // Return: CMIUtilString - Binary number in text. |
| // Throws: None. |
| //-- |
| CMIUtilString CMIUtilString::FormatBinary( const MIuint64 vnDecimal ) |
| { |
| CMIUtilString strBinaryNumber; |
| |
| const MIuint nConstBits = 64; |
| MIuint nRem[ nConstBits + 1 ]; |
| MIint i = 0; |
| MIuint nLen = 0; |
| MIuint64 nNum = vnDecimal; |
| while( (nNum > 0) && (nLen < nConstBits) ) |
| { |
| nRem[ i++ ] = nNum % 2; |
| nNum = nNum >> 1; |
| nLen++; |
| } |
| MIchar pN[ nConstBits + 1 ]; |
| MIuint j = 0; |
| for( i = nLen; i > 0; --i, j++ ) |
| { |
| pN[ j ] = '0' + nRem[ i - 1 ]; |
| } |
| pN[ j ] = 0; // String NUL termination |
| |
| strBinaryNumber = CMIUtilString::Format( "0b%s", &pN[ 0 ] ); |
| |
| return strBinaryNumber; |
| } |
| |