2012-08-23 01:17:09 +08:00
//===-- OptionValueArray.cpp ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
# include "lldb/Interpreter/OptionValueArray.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
# include "lldb/Core/Stream.h"
2015-01-16 04:08:35 +08:00
# include "lldb/Host/StringConvert.h"
2012-08-23 01:17:09 +08:00
# include "lldb/Interpreter/Args.h"
using namespace lldb ;
using namespace lldb_private ;
void
OptionValueArray : : DumpValue ( const ExecutionContext * exe_ctx , Stream & strm , uint32_t dump_mask )
{
const Type array_element_type = ConvertTypeMaskToType ( m_type_mask ) ;
if ( dump_mask & eDumpOptionType )
{
if ( ( GetType ( ) = = eTypeArray ) & & ( m_type_mask ! = eTypeInvalid ) )
strm . Printf ( " (%s of %ss) " , GetTypeAsCString ( ) , GetBuiltinTypeAsCString ( array_element_type ) ) ;
else
strm . Printf ( " (%s) " , GetTypeAsCString ( ) ) ;
}
if ( dump_mask & eDumpOptionValue )
{
if ( dump_mask & eDumpOptionType )
strm . Printf ( " =%s " , ( m_values . size ( ) > 0 ) ? " \n " : " " ) ;
strm . IndentMore ( ) ;
const uint32_t size = m_values . size ( ) ;
for ( uint32_t i = 0 ; i < size ; + + i )
{
strm . Indent ( ) ;
strm . Printf ( " [%u]: " , i ) ;
const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0 ;
switch ( array_element_type )
{
default :
case eTypeArray :
case eTypeDictionary :
case eTypeProperties :
case eTypeFileSpecList :
case eTypePathMap :
m_values [ i ] - > DumpValue ( exe_ctx , strm , dump_mask | extra_dump_options ) ;
break ;
case eTypeBoolean :
2015-01-13 04:44:02 +08:00
case eTypeChar :
2012-08-23 01:17:09 +08:00
case eTypeEnum :
case eTypeFileSpec :
case eTypeFormat :
case eTypeSInt64 :
case eTypeString :
case eTypeUInt64 :
case eTypeUUID :
// No need to show the type for dictionaries of simple items
m_values [ i ] - > DumpValue ( exe_ctx , strm , ( dump_mask & ( ~ eDumpOptionType ) ) | extra_dump_options ) ;
break ;
}
if ( i < ( size - 1 ) )
strm . EOL ( ) ;
}
strm . IndentLess ( ) ;
}
}
Error
OptionValueArray : : SetValueFromCString ( const char * value , VarSetOperationType op )
{
Args args ( value ) ;
2015-01-14 05:13:08 +08:00
NotifyValueChanged ( ) ;
2012-08-23 01:17:09 +08:00
return SetArgs ( args , op ) ;
}
lldb : : OptionValueSP
OptionValueArray : : GetSubValue ( const ExecutionContext * exe_ctx ,
const char * name ,
bool will_modify ,
Error & error ) const
{
if ( name & & name [ 0 ] = = ' [ ' )
{
const char * end_bracket = strchr ( name + 1 , ' ] ' ) ;
if ( end_bracket )
{
2014-04-20 08:31:37 +08:00
const char * sub_value = nullptr ;
2012-08-23 01:17:09 +08:00
if ( end_bracket [ 1 ] )
sub_value = end_bracket + 1 ;
std : : string index_str ( name + 1 , end_bracket ) ;
const size_t array_count = m_values . size ( ) ;
2015-01-16 04:08:35 +08:00
int32_t idx = StringConvert : : ToSInt32 ( index_str . c_str ( ) , INT32_MAX , 0 , nullptr ) ;
2012-08-23 01:17:09 +08:00
if ( idx ! = INT32_MAX )
{
;
uint32_t new_idx = UINT32_MAX ;
if ( idx < 0 )
{
// Access from the end of the array if the index is negative
new_idx = array_count - idx ;
}
else
{
// Just a standard index
new_idx = idx ;
}
if ( new_idx < array_count )
{
if ( m_values [ new_idx ] )
{
if ( sub_value )
return m_values [ new_idx ] - > GetSubValue ( exe_ctx , sub_value , will_modify , error ) ;
else
return m_values [ new_idx ] ;
}
}
else
{
if ( array_count = = 0 )
error . SetErrorStringWithFormat ( " index %i is not valid for an empty array " , idx ) ;
else if ( idx > 0 )
2012-11-30 05:49:15 +08:00
error . SetErrorStringWithFormat ( " index %i out of range, valid values are 0 through % " PRIu64 , idx , ( uint64_t ) ( array_count - 1 ) ) ;
2012-08-23 01:17:09 +08:00
else
2012-11-30 05:49:15 +08:00
error . SetErrorStringWithFormat ( " negative index %i out of range, valid values are -1 through -% " PRIu64 , idx , ( uint64_t ) array_count ) ;
2012-08-23 01:17:09 +08:00
}
}
}
}
else
{
error . SetErrorStringWithFormat ( " invalid value path '%s', %s values only support '[<index>]' subvalues where <index> is a positive or negative array index " , name , GetTypeAsCString ( ) ) ;
}
return OptionValueSP ( ) ;
}
size_t
OptionValueArray : : GetArgs ( Args & args ) const
{
const uint32_t size = m_values . size ( ) ;
std : : vector < const char * > argv ;
for ( uint32_t i = 0 ; i < size ; + + i )
{
const char * string_value = m_values [ i ] - > GetStringValue ( ) ;
if ( string_value )
argv . push_back ( string_value ) ;
}
if ( argv . empty ( ) )
args . Clear ( ) ;
else
args . SetArguments ( argv . size ( ) , & argv [ 0 ] ) ;
return args . GetArgumentCount ( ) ;
}
Error
OptionValueArray : : SetArgs ( const Args & args , VarSetOperationType op )
{
Error error ;
const size_t argc = args . GetArgumentCount ( ) ;
switch ( op )
{
case eVarSetOperationInvalid :
error . SetErrorString ( " unsupported operation " ) ;
break ;
case eVarSetOperationInsertBefore :
case eVarSetOperationInsertAfter :
if ( argc > 1 )
{
2015-01-16 04:08:35 +08:00
uint32_t idx = StringConvert : : ToUInt32 ( args . GetArgumentAtIndex ( 0 ) , UINT32_MAX ) ;
2012-08-23 01:17:09 +08:00
const uint32_t count = GetSize ( ) ;
if ( idx > count )
{
error . SetErrorStringWithFormat ( " invalid insert array index %u, index must be 0 through %u " , idx , count ) ;
}
else
{
if ( op = = eVarSetOperationInsertAfter )
+ + idx ;
for ( size_t i = 1 ; i < argc ; + + i , + + idx )
{
lldb : : OptionValueSP value_sp ( CreateValueFromCStringForTypeMask ( args . GetArgumentAtIndex ( i ) ,
m_type_mask ,
error ) ) ;
if ( value_sp )
{
if ( error . Fail ( ) )
return error ;
if ( idx > = m_values . size ( ) )
m_values . push_back ( value_sp ) ;
else
m_values . insert ( m_values . begin ( ) + idx , value_sp ) ;
}
else
{
error . SetErrorString ( " array of complex types must subclass OptionValueArray " ) ;
return error ;
}
}
}
}
else
{
error . SetErrorString ( " insert operation takes an array index followed by one or more values " ) ;
}
break ;
case eVarSetOperationRemove :
if ( argc > 0 )
{
const uint32_t size = m_values . size ( ) ;
std : : vector < int > remove_indexes ;
bool all_indexes_valid = true ;
size_t i ;
for ( i = 0 ; i < argc ; + + i )
{
2014-04-02 11:51:35 +08:00
const size_t idx =
2015-01-16 04:08:35 +08:00
StringConvert : : ToSInt32 ( args . GetArgumentAtIndex ( i ) , INT32_MAX ) ;
2012-08-23 01:17:09 +08:00
if ( idx > = size )
{
all_indexes_valid = false ;
break ;
}
else
remove_indexes . push_back ( idx ) ;
}
if ( all_indexes_valid )
{
size_t num_remove_indexes = remove_indexes . size ( ) ;
if ( num_remove_indexes )
{
// Sort and then erase in reverse so indexes are always valid
if ( num_remove_indexes > 1 )
{
std : : sort ( remove_indexes . begin ( ) , remove_indexes . end ( ) ) ;
for ( std : : vector < int > : : const_reverse_iterator pos = remove_indexes . rbegin ( ) , end = remove_indexes . rend ( ) ; pos ! = end ; + + pos )
{
m_values . erase ( m_values . begin ( ) + * pos ) ;
}
}
else
{
// Only one index
m_values . erase ( m_values . begin ( ) + remove_indexes . front ( ) ) ;
}
}
}
else
{
error . SetErrorStringWithFormat ( " invalid array index '%s', aborting remove operation " , args . GetArgumentAtIndex ( i ) ) ;
}
}
else
{
error . SetErrorString ( " remove operation takes one or more array indices " ) ;
}
break ;
case eVarSetOperationClear :
Clear ( ) ;
break ;
case eVarSetOperationReplace :
if ( argc > 1 )
{
2015-01-16 04:08:35 +08:00
uint32_t idx = StringConvert : : ToUInt32 ( args . GetArgumentAtIndex ( 0 ) , UINT32_MAX ) ;
2012-08-23 01:17:09 +08:00
const uint32_t count = GetSize ( ) ;
if ( idx > count )
{
error . SetErrorStringWithFormat ( " invalid replace array index %u, index must be 0 through %u " , idx , count ) ;
}
else
{
for ( size_t i = 1 ; i < argc ; + + i , + + idx )
{
lldb : : OptionValueSP value_sp ( CreateValueFromCStringForTypeMask ( args . GetArgumentAtIndex ( i ) ,
m_type_mask ,
error ) ) ;
if ( value_sp )
{
if ( error . Fail ( ) )
return error ;
if ( idx < count )
m_values [ idx ] = value_sp ;
else
m_values . push_back ( value_sp ) ;
}
else
{
error . SetErrorString ( " array of complex types must subclass OptionValueArray " ) ;
return error ;
}
}
}
}
else
{
error . SetErrorString ( " replace operation takes an array index followed by one or more values " ) ;
}
break ;
case eVarSetOperationAssign :
m_values . clear ( ) ;
// Fall through to append case
case eVarSetOperationAppend :
for ( size_t i = 0 ; i < argc ; + + i )
{
lldb : : OptionValueSP value_sp ( CreateValueFromCStringForTypeMask ( args . GetArgumentAtIndex ( i ) ,
m_type_mask ,
error ) ) ;
if ( value_sp )
{
if ( error . Fail ( ) )
return error ;
m_value_was_set = true ;
AppendValue ( value_sp ) ;
}
else
{
error . SetErrorString ( " array of complex types must subclass OptionValueArray " ) ;
}
}
break ;
}
return error ;
}
lldb : : OptionValueSP
OptionValueArray : : DeepCopy ( ) const
{
OptionValueArray * copied_array = new OptionValueArray ( m_type_mask , m_raw_value_dump ) ;
lldb : : OptionValueSP copied_value_sp ( copied_array ) ;
const uint32_t size = m_values . size ( ) ;
for ( uint32_t i = 0 ; i < size ; + + i )
{
copied_array - > AppendValue ( m_values [ i ] - > DeepCopy ( ) ) ;
}
return copied_value_sp ;
}