mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-13 21:06:05 +00:00

Since interaction with the python interpreter is moving towards being more isolated, we won't be able to include this header from normal files anymore, all includes of it should be localized to the python library which will live under source/bindings/API/Python after a future patch. None of the files that were including this header actually depended on it anyway, so it was just a dead include in every single instance. llvm-svn: 238581
439 lines
15 KiB
C++
439 lines
15 KiB
C++
//===-- OptionValueDictionary.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/OptionValueDictionary.h"
|
|
|
|
// C Includes
|
|
// C++ Includes
|
|
// Other libraries and framework includes
|
|
#include "llvm/ADT/StringRef.h"
|
|
// Project includes
|
|
#include "lldb/Core/State.h"
|
|
#include "lldb/DataFormatters/FormatManager.h"
|
|
#include "lldb/Interpreter/Args.h"
|
|
#include "lldb/Interpreter/OptionValueString.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
void
|
|
OptionValueDictionary::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)
|
|
{
|
|
const Type dict_type = ConvertTypeMaskToType (m_type_mask);
|
|
if (dump_mask & eDumpOptionType)
|
|
{
|
|
if (m_type_mask != eTypeInvalid)
|
|
strm.Printf ("(%s of %ss)", GetTypeAsCString(), GetBuiltinTypeAsCString(dict_type));
|
|
else
|
|
strm.Printf ("(%s)", GetTypeAsCString());
|
|
}
|
|
if (dump_mask & eDumpOptionValue)
|
|
{
|
|
if (dump_mask & eDumpOptionType)
|
|
strm.PutCString (" =");
|
|
|
|
collection::iterator pos, end = m_values.end();
|
|
|
|
strm.IndentMore();
|
|
|
|
for (pos = m_values.begin(); pos != end; ++pos)
|
|
{
|
|
OptionValue *option_value = pos->second.get();
|
|
strm.EOL();
|
|
strm.Indent(pos->first.GetCString());
|
|
|
|
const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
|
|
switch (dict_type)
|
|
{
|
|
default:
|
|
case eTypeArray:
|
|
case eTypeDictionary:
|
|
case eTypeProperties:
|
|
case eTypeFileSpecList:
|
|
case eTypePathMap:
|
|
strm.PutChar (' ');
|
|
option_value->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);
|
|
break;
|
|
|
|
case eTypeBoolean:
|
|
case eTypeChar:
|
|
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
|
|
strm.PutCString("=");
|
|
option_value->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) | extra_dump_options);
|
|
break;
|
|
}
|
|
}
|
|
strm.IndentLess();
|
|
}
|
|
|
|
}
|
|
|
|
size_t
|
|
OptionValueDictionary::GetArgs (Args &args) const
|
|
{
|
|
args.Clear();
|
|
collection::const_iterator pos, end = m_values.end();
|
|
for (pos = m_values.begin(); pos != end; ++pos)
|
|
{
|
|
StreamString strm;
|
|
strm.Printf("%s=", pos->first.GetCString());
|
|
pos->second->DumpValue(nullptr, strm, eDumpOptionValue|eDumpOptionRaw);
|
|
args.AppendArgument(strm.GetString().c_str());
|
|
}
|
|
return args.GetArgumentCount();
|
|
}
|
|
|
|
Error
|
|
OptionValueDictionary::SetArgs (const Args &args, VarSetOperationType op)
|
|
{
|
|
Error error;
|
|
const size_t argc = args.GetArgumentCount();
|
|
switch (op)
|
|
{
|
|
case eVarSetOperationClear:
|
|
Clear();
|
|
break;
|
|
|
|
case eVarSetOperationAppend:
|
|
case eVarSetOperationReplace:
|
|
case eVarSetOperationAssign:
|
|
if (argc > 0)
|
|
{
|
|
for (size_t i=0; i<argc; ++i)
|
|
{
|
|
llvm::StringRef key_and_value(args.GetArgumentAtIndex(i));
|
|
if (!key_and_value.empty())
|
|
{
|
|
std::pair<llvm::StringRef, llvm::StringRef> kvp(key_and_value.split('='));
|
|
llvm::StringRef key = kvp.first;
|
|
bool key_valid = false;
|
|
if (!key.empty())
|
|
{
|
|
if (key.front() == '[')
|
|
{
|
|
// Key name starts with '[', so the the key value must be in single or double quotes like:
|
|
// ['<key>']
|
|
// ["<key>"]
|
|
if ((key.size() > 2) && (key.back() == ']'))
|
|
{
|
|
// Strip leading '[' and trailing ']'
|
|
key = key.substr(1, key.size()-2);
|
|
const char quote_char = key.front();
|
|
if ((quote_char == '\'') || (quote_char == '"'))
|
|
{
|
|
if ((key.size() > 2) && (key.back() == quote_char))
|
|
{
|
|
// Strip the quotes
|
|
key = key.substr(1, key.size()-2);
|
|
key_valid = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// square brackets, no quotes
|
|
key_valid = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No square brackets or quotes
|
|
key_valid = true;
|
|
}
|
|
}
|
|
if (!key_valid)
|
|
{
|
|
error.SetErrorStringWithFormat("invalid key \"%s\", the key must be a bare string or surrounded by brackets with optional quotes: [<key>] or ['<key>'] or [\"<key>\"]", kvp.first.str().c_str());
|
|
return error;
|
|
}
|
|
|
|
lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (kvp.second.data(),
|
|
m_type_mask,
|
|
error));
|
|
if (value_sp)
|
|
{
|
|
if (error.Fail())
|
|
return error;
|
|
m_value_was_set = true;
|
|
SetValueForKey (ConstString(key), value_sp, true);
|
|
}
|
|
else
|
|
{
|
|
error.SetErrorString("dictionaries that can contain multiple types must subclass OptionValueArray");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error.SetErrorString("empty argument");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error.SetErrorString("assign operation takes one or more key=value arguments");
|
|
}
|
|
break;
|
|
|
|
case eVarSetOperationRemove:
|
|
if (argc > 0)
|
|
{
|
|
for (size_t i=0; i<argc; ++i)
|
|
{
|
|
ConstString key(args.GetArgumentAtIndex(i));
|
|
if (!DeleteValueForKey(key))
|
|
{
|
|
error.SetErrorStringWithFormat("no value found named '%s', aborting remove operation", key.GetCString());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error.SetErrorString("remove operation takes one or more key arguments");
|
|
}
|
|
break;
|
|
|
|
case eVarSetOperationInsertBefore:
|
|
case eVarSetOperationInsertAfter:
|
|
case eVarSetOperationInvalid:
|
|
error = OptionValue::SetValueFromString (llvm::StringRef(), op);
|
|
break;
|
|
}
|
|
return error;
|
|
}
|
|
|
|
Error
|
|
OptionValueDictionary::SetValueFromString (llvm::StringRef value, VarSetOperationType op)
|
|
{
|
|
Args args(value.str().c_str());
|
|
Error error = SetArgs (args, op);
|
|
if (error.Success())
|
|
NotifyValueChanged();
|
|
return error;
|
|
}
|
|
|
|
lldb::OptionValueSP
|
|
OptionValueDictionary::GetSubValue (const ExecutionContext *exe_ctx, const char *name, bool will_modify, Error &error) const
|
|
{
|
|
lldb::OptionValueSP value_sp;
|
|
|
|
if (name && name[0])
|
|
{
|
|
const char *sub_name = nullptr;
|
|
ConstString key;
|
|
const char *open_bracket = ::strchr (name, '[');
|
|
|
|
if (open_bracket)
|
|
{
|
|
const char *key_start = open_bracket + 1;
|
|
const char *key_end = nullptr;
|
|
switch (open_bracket[1])
|
|
{
|
|
case '\'':
|
|
++key_start;
|
|
key_end = strchr(key_start, '\'');
|
|
if (key_end)
|
|
{
|
|
if (key_end[1] == ']')
|
|
{
|
|
if (key_end[2])
|
|
sub_name = key_end + 2;
|
|
}
|
|
else
|
|
{
|
|
error.SetErrorStringWithFormat ("invalid value path '%s', single quoted key names must be formatted as ['<key>'] where <key> is a string that doesn't contain quotes", name);
|
|
return value_sp;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
error.SetErrorString ("missing '] key name terminator, key name started with ['");
|
|
return value_sp;
|
|
}
|
|
break;
|
|
case '"':
|
|
++key_start;
|
|
key_end = strchr(key_start, '"');
|
|
if (key_end)
|
|
{
|
|
if (key_end[1] == ']')
|
|
{
|
|
if (key_end[2])
|
|
sub_name = key_end + 2;
|
|
break;
|
|
}
|
|
error.SetErrorStringWithFormat ("invalid value path '%s', double quoted key names must be formatted as [\"<key>\"] where <key> is a string that doesn't contain quotes", name);
|
|
return value_sp;
|
|
}
|
|
else
|
|
{
|
|
error.SetErrorString ("missing \"] key name terminator, key name started with [\"");
|
|
return value_sp;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
key_end = strchr(key_start, ']');
|
|
if (key_end)
|
|
{
|
|
if (key_end[1])
|
|
sub_name = key_end + 1;
|
|
}
|
|
else
|
|
{
|
|
error.SetErrorString ("missing ] key name terminator, key name started with [");
|
|
return value_sp;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (key_start && key_end)
|
|
{
|
|
key.SetCStringWithLength (key_start, key_end - key_start);
|
|
|
|
value_sp = GetValueForKey (key);
|
|
if (value_sp)
|
|
{
|
|
if (sub_name)
|
|
return value_sp->GetSubValue (exe_ctx, sub_name, will_modify, error);
|
|
}
|
|
else
|
|
{
|
|
error.SetErrorStringWithFormat("dictionary does not contain a value for the key name '%s'", key.GetCString());
|
|
}
|
|
}
|
|
}
|
|
if (!value_sp && error.AsCString() == nullptr)
|
|
{
|
|
error.SetErrorStringWithFormat ("invalid value path '%s', %s values only support '[<key>]' subvalues where <key> a string value optionally delimitted by single or double quotes",
|
|
name,
|
|
GetTypeAsCString());
|
|
}
|
|
}
|
|
return value_sp;
|
|
}
|
|
|
|
Error
|
|
OptionValueDictionary::SetSubValue (const ExecutionContext *exe_ctx, VarSetOperationType op, const char *name, const char *value)
|
|
{
|
|
Error error;
|
|
const bool will_modify = true;
|
|
lldb::OptionValueSP value_sp (GetSubValue (exe_ctx, name, will_modify, error));
|
|
if (value_sp)
|
|
error = value_sp->SetValueFromString(value, op);
|
|
else
|
|
{
|
|
if (error.AsCString() == nullptr)
|
|
error.SetErrorStringWithFormat("invalid value path '%s'", name);
|
|
}
|
|
return error;
|
|
}
|
|
|
|
|
|
lldb::OptionValueSP
|
|
OptionValueDictionary::GetValueForKey (const ConstString &key) const
|
|
{
|
|
lldb::OptionValueSP value_sp;
|
|
collection::const_iterator pos = m_values.find (key);
|
|
if (pos != m_values.end())
|
|
value_sp = pos->second;
|
|
return value_sp;
|
|
}
|
|
|
|
const char *
|
|
OptionValueDictionary::GetStringValueForKey (const ConstString &key)
|
|
{
|
|
collection::const_iterator pos = m_values.find (key);
|
|
if (pos != m_values.end())
|
|
{
|
|
OptionValueString *string_value = pos->second->GetAsString();
|
|
if (string_value)
|
|
return string_value->GetCurrentValue();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
bool
|
|
OptionValueDictionary::SetStringValueForKey (const ConstString &key,
|
|
const char *value,
|
|
bool can_replace)
|
|
{
|
|
collection::const_iterator pos = m_values.find (key);
|
|
if (pos != m_values.end())
|
|
{
|
|
if (!can_replace)
|
|
return false;
|
|
if (pos->second->GetType() == OptionValue::eTypeString)
|
|
{
|
|
pos->second->SetValueFromString(value);
|
|
return true;
|
|
}
|
|
}
|
|
m_values[key] = OptionValueSP (new OptionValueString (value));
|
|
return true;
|
|
|
|
}
|
|
|
|
bool
|
|
OptionValueDictionary::SetValueForKey (const ConstString &key,
|
|
const lldb::OptionValueSP &value_sp,
|
|
bool can_replace)
|
|
{
|
|
// Make sure the value_sp object is allowed to contain
|
|
// values of the type passed in...
|
|
if (value_sp && (m_type_mask & value_sp->GetTypeAsMask()))
|
|
{
|
|
if (!can_replace)
|
|
{
|
|
collection::const_iterator pos = m_values.find (key);
|
|
if (pos != m_values.end())
|
|
return false;
|
|
}
|
|
m_values[key] = value_sp;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
OptionValueDictionary::DeleteValueForKey (const ConstString &key)
|
|
{
|
|
collection::iterator pos = m_values.find (key);
|
|
if (pos != m_values.end())
|
|
{
|
|
m_values.erase(pos);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
lldb::OptionValueSP
|
|
OptionValueDictionary::DeepCopy () const
|
|
{
|
|
OptionValueDictionary *copied_dict = new OptionValueDictionary (m_type_mask, m_raw_value_dump);
|
|
lldb::OptionValueSP copied_value_sp(copied_dict);
|
|
collection::const_iterator pos, end = m_values.end();
|
|
for (pos = m_values.begin(); pos != end; ++pos)
|
|
{
|
|
StreamString strm;
|
|
strm.Printf("%s=", pos->first.GetCString());
|
|
copied_dict->SetValueForKey (pos->first, pos->second->DeepCopy(), true);
|
|
}
|
|
return copied_value_sp;
|
|
}
|
|
|