diff options
Diffstat (limited to 'tools/lldb-mi/MIUtilString.cpp')
-rw-r--r-- | tools/lldb-mi/MIUtilString.cpp | 680 |
1 files changed, 680 insertions, 0 deletions
diff --git a/tools/lldb-mi/MIUtilString.cpp b/tools/lldb-mi/MIUtilString.cpp new file mode 100644 index 000000000000..11c246290cab --- /dev/null +++ b/tools/lldb-mi/MIUtilString.cpp @@ -0,0 +1,680 @@ +//===-- 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. Quotes that are embedded in the +// the string as string formatted quotes are ignored (proceeded by a '\\') i.e. +// "\"MI GDB local C++.cpp\":88". +// 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 cBckSlash = '\\'; + const MIchar cQuote = '"'; + MIint nPosQ = find( cQuote ); + MIint nPosQ2 = (MIint) std::string::npos; + if( nPosQ != (MIint) std::string::npos ) + { + nPosQ2 = nPosQ + 1; + while( nPosQ2 < strLen ) + { + nPosQ2 = find( cQuote, nPosQ2 ); + if( (nPosQ2 == (MIint) std::string::npos) || (at( nPosQ2 - 1 ) != cBckSlash) ) + break; + nPosQ2++; + } + 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 MIint 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; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Remove from a string doubled up characters so only one set left. Characters +// are only removed if the previous character is already a same character. +// Type: Method. +// Args: vChar - (R) The character to search for and remove adjacent duplicates. +// Return: CMIUtilString - New version of the string. +// Throws: None. +//-- +CMIUtilString CMIUtilString::RemoveRepeatedCharacters( const MIchar vChar ) +{ + return RemoveRepeatedCharacters( 0, vChar ); +} + +//++ ------------------------------------------------------------------------------------ +// Details: Recursively remove from a string doubled up characters so only one set left. +// Characters are only removed if the previous character is already a same +// character. +// Type: Method. +// Args: vChar - (R) The character to search for and remove adjacent duplicates. +// vnPos - (R) Character position in the string. +// Return: CMIUtilString - New version of the string. +// Throws: None. +//-- +CMIUtilString CMIUtilString::RemoveRepeatedCharacters( const MIint vnPos, const MIchar vChar ) +{ + const MIchar cQuote = '"'; + + // Look for first quote of two + MIint nPos = find( cQuote, vnPos ); + if( nPos == (MIint) std::string::npos ) + return *this; + + const MIint nPosNext = nPos + 1; + if( nPosNext > (MIint) length() ) + return *this; + + if( at( nPosNext ) == cQuote ) + { + *this = substr( 0, nPos ) + substr( nPosNext, length() ); + RemoveRepeatedCharacters( nPosNext, vChar ); + } + + return *this; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Is the text in *this string surrounded by quotes. +// Type: Method. +// Args: None. +// Return: bool - True = Yes string is quoted, false = no quoted. +// Throws: None. +//-- +bool CMIUtilString::IsQuoted( void ) const +{ + const MIchar cQuote = '"'; + + if( at( 0 ) != cQuote ) + return false; + + const MIint nLen = length(); + if( (nLen > 0) && (at( nLen - 1 ) != cQuote) ) + return false; + + return true; +} +
\ No newline at end of file |