diff options
Diffstat (limited to 'lldb/source/Core/UserSettingsController.cpp')
-rw-r--r-- | lldb/source/Core/UserSettingsController.cpp | 1857 |
1 files changed, 1857 insertions, 0 deletions
diff --git a/lldb/source/Core/UserSettingsController.cpp b/lldb/source/Core/UserSettingsController.cpp new file mode 100644 index 00000000000..554ea76bedd --- /dev/null +++ b/lldb/source/Core/UserSettingsController.cpp @@ -0,0 +1,1857 @@ +//====-- UserSettingsController.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <string.h> +#include <algorithm> + +#include "lldb/Core/UserSettingsController.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Stream.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Interpreter/CommandInterpreter.h" + +using namespace lldb_private; + +UserSettingsController::UserSettingsController (const char *level_name, + const lldb::UserSettingsControllerSP &parent) : + m_default_settings (), + m_settings (), + m_children (), + m_pending_settings (), + m_live_settings (), + m_children_mutex (Mutex::eMutexTypeNormal), + m_pending_settings_mutex (Mutex::eMutexTypeNormal), + m_live_settings_mutex (Mutex::eMutexTypeNormal) +{ + m_settings.parent = parent; + m_settings.level_name.SetCString (level_name); +} + +UserSettingsController::~UserSettingsController () +{ + m_live_settings.clear(); +} + +void +UserSettingsController::InitializeGlobalVariables () +{ + static bool global_initialized = false; + int num_entries; + const char *prefix = GetLevelName().AsCString(); + + if (! global_initialized) + { + num_entries = m_settings.global_settings.size(); + for (int i = 0; i < num_entries; ++i) + { + SettingEntry &entry = m_settings.global_settings[i]; + if (entry.default_value != NULL) + { + StreamString full_name; + if (prefix[0] != '\0') + full_name.Printf ("%s.%s", prefix, entry.var_name); + else + full_name.Printf ("%s", entry.var_name); + SetVariable (full_name.GetData(), entry.default_value, lldb::eVarSetOperationAssign, false); + } + else if ((entry.var_type == lldb::eSetVarTypeEnum) + && (entry.enum_values != NULL)) + { + StreamString full_name; + if (prefix[0] != '\0') + full_name.Printf ("%s.%s", prefix, entry.var_name); + else + full_name.Printf ("%s", entry.var_name); + SetVariable (full_name.GetData(), entry.enum_values[0].string_value, lldb::eVarSetOperationAssign, + false); + } + } + global_initialized = true; + } +} + +const lldb::UserSettingsControllerSP & +UserSettingsController::GetParent () +{ + return m_settings.parent; +} + +void +UserSettingsController::RegisterChild (const lldb::UserSettingsControllerSP &child) +{ + Mutex::Locker locker (m_children_mutex); + + // Verify child is not already in m_children. + size_t num_children = m_children.size(); + bool found = false; + for (size_t i = 0; i < num_children; ++i) + { + if (m_children[i].get() == child.get()) + found = true; + } + + // Add child to m_children. + if (! found) + m_children.push_back (child); +} + +const ConstString & +UserSettingsController::GetLevelName () +{ + return m_settings.level_name; +} + +size_t +UserSettingsController::GetNumChildren () +{ + return m_children.size(); +} + +const lldb::UserSettingsControllerSP +UserSettingsController::GetChildAtIndex (size_t index) +{ + if (index < m_children.size()) + return m_children[index]; + + lldb::UserSettingsControllerSP dummy_value; + + return dummy_value; +} + +const SettingEntry * +UserSettingsController::GetGlobalEntry (const ConstString &var_name) +{ + + for (int i = 0; i < m_settings.global_settings.size(); ++i) + { + SettingEntry &entry = m_settings.global_settings[i]; + ConstString entry_name (entry.var_name); + if (entry_name == var_name) + return &entry; + } + + return NULL; +} + +const SettingEntry * +UserSettingsController::GetInstanceEntry (const ConstString &const_var_name) +{ + + for (int i = 0; i < m_settings.instance_settings.size(); ++i) + { + SettingEntry &entry = m_settings.instance_settings[i]; + ConstString entry_name (entry.var_name); + if (entry_name == const_var_name) + return &entry; + } + + return NULL; +} + +void +UserSettingsController::BuildParentPrefix (std::string &parent_prefix) +{ + lldb::UserSettingsControllerSP parent = GetParent(); + if (parent.get() != NULL) + { + parent->BuildParentPrefix (parent_prefix); + if (parent_prefix.length() > 0) + parent_prefix.append ("."); + } + parent_prefix.append (GetLevelName().AsCString()); +} + +void +UserSettingsController::RemoveChild (const lldb::UserSettingsControllerSP &child) +{ + Mutex::Locker locker (m_children_mutex); + std::vector<lldb::UserSettingsControllerSP>::iterator pos, end = m_children.end(); + + for (pos = m_children.begin(); pos != end; ++pos) + { + lldb::UserSettingsControllerSP entry = *pos; + if (entry == child) + { + m_children.erase (pos); + break; + } + } +} + +Error +UserSettingsController::SetVariable (const char *full_dot_name, + const char *value, + const lldb::VarSetOperationType op, + const bool override, + const char *index_value) +{ + Error err; + ConstString const_var_name; + const ConstString &default_name = InstanceSettings::GetDefaultName(); + + Args names = UserSettingsController::BreakNameIntoPieces (full_dot_name); + int num_pieces = names.GetArgumentCount(); + + if (num_pieces < 1) + { + err.SetErrorStringWithFormat ("'%s' is not a valid variable name; cannot assign value.\n", full_dot_name); + return err; + } + + ConstString prefix (names.GetArgumentAtIndex (0)); + + if ((prefix == m_settings.level_name) + || (m_settings.level_name.GetLength() == 0)) + { + + if (prefix == m_settings.level_name) + { + names.Shift (); + num_pieces = names.GetArgumentCount(); + } + + if (num_pieces == 0) + { + err.SetErrorString ("No variable name specified; cannot assign value.\n"); + return err; + } + else if (num_pieces == 1) + { + + // Must be one of the class-wide settings. + + const_var_name.SetCString (names.GetArgumentAtIndex (0)); + const SettingEntry *entry = GetGlobalEntry (const_var_name); + if (entry) + { + UserSettingsController::VerifyOperationForType (entry->var_type, op, const_var_name, err); + + if (err.Fail()) + return err; + + if ((value == NULL || value[0] == '\0') + && (op == lldb::eVarSetOperationAssign)) + { + if (entry->var_type != lldb::eSetVarTypeEnum) + value = entry->default_value; + else + value = entry->enum_values[0].string_value; + } + UpdateGlobalVariable (const_var_name, index_value, value, *entry, op, err); + } + else + { + // MIGHT be instance variable, to be for ALL instances. + + entry = GetInstanceEntry (const_var_name); + if (entry == NULL) + { + err.SetErrorStringWithFormat ("Unable to find variable '%s.%s'; cannot assign value.\n", + prefix.AsCString(), const_var_name.AsCString()); + return err; + } + else + { + UserSettingsController::VerifyOperationForType (entry->var_type, op, const_var_name, err); + + if (err.Fail()) + return err; + + if ((value == NULL || value[0] == '\0') + && (op == lldb::eVarSetOperationAssign)) + { + if (entry->var_type != lldb::eSetVarTypeEnum) + value = entry->default_value; + else + value = entry->enum_values[0].string_value; + } + + m_default_settings->UpdateInstanceSettingsVariable (const_var_name, index_value, value, + default_name, *entry, op, err, true); + if (override) + { + OverrideAllInstances (const_var_name, value, op, index_value, err); + + // Update all pending records as well. + std::map<std::string, lldb::InstanceSettingsSP>::iterator pos, end = m_pending_settings.end(); + for (pos = m_pending_settings.begin(); pos != end; end++) + { + const ConstString instance_name (pos->first.c_str()); + lldb::InstanceSettingsSP setting_sp = pos->second; + setting_sp->UpdateInstanceSettingsVariable (const_var_name, index_value, value, + instance_name, *entry, op, err, true); + } + } + } + } + } + else + { + // Either a child's setting or an instance setting. + + if (names.GetArgumentAtIndex(0)[0] == '[') + { + // An instance setting. Supposedly. + + ConstString instance_name (names.GetArgumentAtIndex (0)); + + // First verify that there is only one more name. + + names.Shift(); + + if (names.GetArgumentCount() != 1) + { + err.SetErrorStringWithFormat ("Invalid variable name format '%s'; cannot assign value.\n", + full_dot_name); + return err; + } + + // Next verify that it is a valid instance setting name. + + const_var_name.SetCString (names.GetArgumentAtIndex (0)); + const SettingEntry *entry = GetInstanceEntry (const_var_name); + + if (entry == NULL) + { + err.SetErrorStringWithFormat ("Unknown instance variable '%s'; cannot assign value.\n", + const_var_name.AsCString()); + return err; + } + + UserSettingsController::VerifyOperationForType (entry->var_type, op, const_var_name, err); + + if (err.Fail()) + return err; + + if ((value == NULL || value[0] == '\0') + && (op == lldb::eVarSetOperationAssign)) + { + if (entry->var_type != lldb::eSetVarTypeEnum) + value = entry->default_value; + else + value = entry->enum_values[0].string_value; + } + + // Now look for existing instance with given instance name; if not found, find or create pending + // setting for instance with given name. + + InstanceSettings *current_settings = FindSettingsForInstance (instance_name); + + if (current_settings != NULL) + { + current_settings->UpdateInstanceSettingsVariable (const_var_name, index_value, value, + instance_name, *entry, op, err, false); + + } + else + { + // Instance does not currently exist; make or update a pending setting for it. + lldb::InstanceSettingsSP current_settings_sp = PendingSettingsForInstance (instance_name); + + // Now we have a settings record, update it appropriately. + + current_settings_sp->UpdateInstanceSettingsVariable (const_var_name, index_value, value, + instance_name, *entry, op, err, true); + + { // Scope for mutex. + Mutex::Locker locker (m_pending_settings_mutex); + m_pending_settings[instance_name.AsCString()] = current_settings_sp; + } + + if (override) + { + OverrideAllInstances (const_var_name, value, op, index_value, err); + + // Update all pending records as well. + std::map<std::string, lldb::InstanceSettingsSP>::iterator pos; + std::map<std::string, lldb::InstanceSettingsSP>::iterator end = m_pending_settings.end(); + for (pos = m_pending_settings.begin(); pos != end; end++) + { + const ConstString tmp_inst_name (pos->first.c_str()); + lldb::InstanceSettingsSP setting_sp = pos->second; + setting_sp->UpdateInstanceSettingsVariable (const_var_name, index_value, value, + tmp_inst_name, *entry, op, err, true); + } + } + } + } + else + { + // A child setting. + lldb::UserSettingsControllerSP child; + ConstString child_prefix (names.GetArgumentAtIndex (0)); + int num_children = GetNumChildren(); + bool found = false; + for (int i = 0; i < num_children && !found; ++i) + { + child = GetChildAtIndex (i); + ConstString current_prefix = child->GetLevelName(); + if (current_prefix == child_prefix) + { + found = true; + std::string new_name; + for (int j = 0; j < names.GetArgumentCount(); ++j) + { + if (j > 0) + new_name += '.'; + new_name += names.GetArgumentAtIndex (j); + } + return child->SetVariable (new_name.c_str(), value, op, override, index_value); + } + } + if (!found) + { + err.SetErrorStringWithFormat ("Unable to find variable '%s'; cannot assign value.\n", + full_dot_name); + return err; + } + } + } + } + else + { + err.SetErrorStringWithFormat ("'%s' is not a valid level name; was expecting '%s'. Cannot assign value.\n", + prefix.AsCString(), m_settings.level_name.AsCString()); + } + + return err; +} + +StringList +UserSettingsController::GetVariable (const char *full_dot_name, lldb::SettableVariableType &var_type) +{ + Args names = UserSettingsController::BreakNameIntoPieces (full_dot_name); + ConstString const_var_name; + StringList value; + + int num_pieces = names.GetArgumentCount(); + + ConstString prefix (names.GetArgumentAtIndex (0)); + const_var_name.SetCString (names.GetArgumentAtIndex (num_pieces - 1)); + + const SettingEntry *global_entry = GetGlobalEntry (const_var_name); + const SettingEntry *instance_entry = GetInstanceEntry (const_var_name); + + if ((prefix != m_settings.level_name) + && (m_settings.level_name.GetLength () > 0)) + { + value.AppendString ("Invalid variable name"); + return value; + } + + // prefix name matched; remove it from names. + if (m_settings.level_name.GetLength() > 0) + names.Shift(); + + // Should we pass this off to a child? If there is more than one name piece left, and the next name piece + // matches a child prefix, then yes. + + lldb::UserSettingsControllerSP child; + if (names.GetArgumentCount() > 1) + { + ConstString child_prefix (names.GetArgumentAtIndex (0)); + bool found = false; + for (int i = 0; i < m_children.size() && !found; ++i) + { + if (child_prefix == m_children[i]->GetLevelName()) + { + found = true; + child = m_children[i]; + std::string new_name; + for (int j = 0; j < names.GetArgumentCount(); ++j) + { + if (j > 0) + new_name += '.'; + new_name += names.GetArgumentAtIndex (j); + } + return child->GetVariable (new_name.c_str(), var_type); + } + } + + if (!found) + { + // Cannot be handled by a child, because name did not match any child prefixes. + // Cannot be a class-wide variable because there are too many name pieces. + + if (instance_entry != NULL) + { + var_type = instance_entry->var_type; + ConstString instance_name (names.GetArgumentAtIndex (0)); + InstanceSettings *current_settings = FindSettingsForInstance (instance_name); + + if (current_settings != NULL) + { + current_settings->GetInstanceSettingsValue (*instance_entry, const_var_name, value); + } + else + { + // Look for instance name setting in pending settings. + + std::string inst_name_str = instance_name.AsCString(); + std::map<std::string, lldb::InstanceSettingsSP>::iterator pos; + + pos = m_pending_settings.find (inst_name_str); + if (pos != m_pending_settings.end()) + { + lldb::InstanceSettingsSP settings_sp = pos->second; + settings_sp->GetInstanceSettingsValue (*instance_entry, const_var_name, value); + } + else + { + // No valid instance name; assume they want the default settings. + m_default_settings->GetInstanceSettingsValue (*instance_entry, const_var_name, value); + } + } + } + else + value.AppendString ("Invalid variable name"); + } + } + else + { + // Only one name left. It must belong to the current level, or be an error. + if ((global_entry == NULL) + && (instance_entry == NULL)) + { + value.AppendString ("Invalid variable name"); + } + else if (global_entry) + { + var_type = global_entry->var_type; + GetGlobalSettingsValue (const_var_name, value); + } + else if (instance_entry) + { + var_type = instance_entry->var_type; + m_default_settings->GetInstanceSettingsValue (*instance_entry, const_var_name, value); + } + } + + return value; +} + +void +UserSettingsController::RemovePendingSettings (const ConstString &instance_name) +{ + std::map<std::string, lldb::InstanceSettingsSP>::iterator pos; + std::string instance_name_str (instance_name.AsCString()); + Mutex::Locker locker (m_pending_settings_mutex); + + m_pending_settings.erase (instance_name_str); +} + +const lldb::InstanceSettingsSP & +UserSettingsController::FindPendingSettings (const ConstString &instance_name) +{ + std::map<std::string, lldb::InstanceSettingsSP>::iterator pos; + std::string instance_name_str (instance_name.AsCString()); + + { // Scope for mutex. + Mutex::Locker locker (m_pending_settings_mutex); + + pos = m_pending_settings.find (instance_name_str); + if (pos != m_pending_settings.end()) + return pos->second; + } + + return m_default_settings; +} + +void +UserSettingsController::CreateDefaultInstanceSettings () +{ + Error err; + const ConstString &default_name = InstanceSettings::GetDefaultName(); + for (int i = 0; i < m_settings.instance_settings.size(); ++i) + { + SettingEntry &entry = m_settings.instance_settings[i]; + ConstString var_name (entry.var_name); + const char *value = entry.default_value; + + if (entry.var_type == lldb::eSetVarTypeEnum) + value = entry.enum_values[0].string_value; + + m_default_settings->UpdateInstanceSettingsVariable (var_name, NULL, value, default_name, entry, + lldb::eVarSetOperationAssign, err, true); + } +} + +void +UserSettingsController::CopyDefaultSettings (const lldb::InstanceSettingsSP &actual_settings, + const ConstString &instance_name, + bool pending) +{ + Error err; + for (int i = 0; i < m_settings.instance_settings.size(); ++i) + { + SettingEntry &entry = m_settings.instance_settings[i]; + ConstString var_name (entry.var_name); + StringList value; + m_default_settings->GetInstanceSettingsValue (entry, var_name, value); + + std::string value_str; + if (value.GetSize() == 1) + value_str.append (value.GetStringAtIndex (0)); + else if (value.GetSize() > 1) + { + for (int j = 0; j < value.GetSize(); ++j) + { + if (j > 0) + value_str.append (" "); + value_str.append (value.GetStringAtIndex (j)); + } + } + + actual_settings->UpdateInstanceSettingsVariable (var_name, NULL, value_str.c_str(), instance_name, entry, + lldb::eVarSetOperationAssign, err, pending); + + } +} + +lldb::InstanceSettingsSP +UserSettingsController::PendingSettingsForInstance (const ConstString &instance_name) +{ + std::string name_str (instance_name.AsCString()); + std::map<std::string, lldb::InstanceSettingsSP>::iterator pos; + Mutex::Locker locker (m_pending_settings_mutex); + + pos = m_pending_settings.find (name_str); + if (pos != m_pending_settings.end()) + { + lldb::InstanceSettingsSP settings_sp = pos->second; + return settings_sp; + } + else + { + lldb::InstanceSettingsSP default_settings_sp = + m_pending_settings[InstanceSettings::GetDefaultName().AsCString()]; + lldb::InstanceSettingsSP new_settings_sp = CreateNewInstanceSettings (); + CopyDefaultSettings (new_settings_sp, instance_name, true); + m_pending_settings[name_str] = new_settings_sp; + return new_settings_sp; + } + + // Should never reach this line. + + lldb::InstanceSettingsSP dummy; + + return dummy; +} + +void +UserSettingsController::GetAllDefaultSettingValues (StreamString &result_stream) +{ + std::string parent_prefix; + BuildParentPrefix (parent_prefix); + const char *prefix = parent_prefix.c_str(); + + for (int i = 0; i < m_settings.instance_settings.size(); ++i) + { + SettingEntry &entry = m_settings.instance_settings[i]; + ConstString var_name (entry.var_name); + StringList tmp_value; + m_default_settings->GetInstanceSettingsValue (entry, var_name, tmp_value); + + StreamString value_string; + + if (tmp_value.GetSize() == 1) + value_string.Printf ("%s", tmp_value.GetStringAtIndex (0)); + else + { + for (int j = 0; j < tmp_value.GetSize(); ++j) + value_string.Printf ("%s ", tmp_value.GetStringAtIndex (j)); + } + + if (! parent_prefix.empty()) // May need to test size() > 0 + result_stream.Printf ("%s.[DEFAULT].%s (%s) = '%s'\n", prefix, var_name.AsCString(), + UserSettingsController::GetTypeString (entry.var_type), value_string.GetData()); + else + result_stream.Printf ("[DEFAULT].%s (%s) = '%s'\n", var_name.AsCString(), + UserSettingsController::GetTypeString (entry.var_type), value_string.GetData()); + } +} + +void +UserSettingsController::GetAllPendingSettingValues (StreamString &result_stream) +{ + //StreamString description; + std::map<std::string, lldb::InstanceSettingsSP>::iterator pos; + + std::string parent_prefix; + BuildParentPrefix (parent_prefix); + const char *prefix = parent_prefix.c_str(); + + for (pos = m_pending_settings.begin(); pos != m_pending_settings.end(); ++pos) + { + std::string tmp_name = pos->first; + lldb::InstanceSettingsSP settings_sp = pos->second; + + const ConstString instance_name (tmp_name.c_str()); + + for (int i = 0; i < m_settings.instance_settings.size(); ++i) + { + SettingEntry &entry = m_settings.instance_settings[i]; + ConstString var_name (entry.var_name); + StringList tmp_value; + settings_sp->GetInstanceSettingsValue (entry, var_name, tmp_value); + + StreamString value_str; + + if (tmp_value.GetSize() == 0) + break; + if (tmp_value.GetSize() == 1) + value_str.Printf ("%s", tmp_value.GetStringAtIndex (0)); + else + { + for (int j = 0; j < tmp_value.GetSize(); ++j) + value_str.Printf ("%s ", tmp_value.GetStringAtIndex (j)); + } + + if (parent_prefix.length() > 0) + { + result_stream.Printf ("%s.%s.%s (%s) = '%s' [pending]\n", prefix, instance_name.AsCString(), + var_name.AsCString(), UserSettingsController::GetTypeString (entry.var_type), + value_str.GetData()); + } + else + { + result_stream.Printf ("%s (%s) = '%s' [pending]\n", var_name.AsCString(), + UserSettingsController::GetTypeString (entry.var_type), + value_str.GetData()); + } + } + } +} + +InstanceSettings * +UserSettingsController::FindSettingsForInstance (const ConstString &instance_name) +{ + std::string instance_name_str (instance_name.AsCString()); + std::map<std::string, InstanceSettings *>::iterator pos; + + pos = m_live_settings.find (instance_name_str); + if (pos != m_live_settings.end ()) + { + InstanceSettings *settings = pos->second; + return settings; + } + + return NULL; +} + +void +UserSettingsController::GetAllInstanceVariableValues (CommandInterpreter &interpreter, + StreamString &result_stream) +{ + std::map<std::string, InstanceSettings *>::iterator pos; + std::string parent_prefix; + BuildParentPrefix (parent_prefix); + const char *prefix = parent_prefix.c_str(); + StreamString description; + + for (pos = m_live_settings.begin(); pos != m_live_settings.end(); ++pos) + { + std::string instance_name = pos->first; + InstanceSettings *settings = pos->second; + + for (int i = 0; i < m_settings.instance_settings.size(); ++i) + { + SettingEntry &entry = m_settings.instance_settings[i]; + const ConstString var_name (entry.var_name); + StringList tmp_value; + settings->GetInstanceSettingsValue (entry, var_name, tmp_value); + StreamString tmp_value_str; + + if (tmp_value.GetSize() == 0) + break; + + if (tmp_value.GetSize() == 1) + tmp_value_str.Printf ("%s", tmp_value.GetStringAtIndex (0)); + else + { + for (int j = 0; j < tmp_value.GetSize(); ++j) + tmp_value_str.Printf ("%s ",tmp_value.GetStringAtIndex (j)); + } + + description.Clear(); + if (parent_prefix.length() > 0) + { + description.Printf ("%s.%s.%s (%s) = '%s'", prefix, instance_name.c_str(), var_name.AsCString(), + UserSettingsController::GetTypeString (entry.var_type), + tmp_value_str.GetData()); + } + else + { + description.Printf ("%s (%s) = '%s'", var_name.AsCString(), + UserSettingsController::GetTypeString (entry.var_type), tmp_value_str.GetData()); + } + result_stream.Printf ("%s\n", description.GetData()); + } + } +} + +void +UserSettingsController::OverrideAllInstances (const ConstString &var_name, + const char *value, + lldb::VarSetOperationType op, + const char *index_value, + Error &err) +{ + std::map<std::string, InstanceSettings *>::iterator pos; + StreamString description; + + for (pos = m_live_settings.begin(); pos != m_live_settings.end(); ++pos) + { + InstanceSettings *settings = pos->second; + StreamString tmp_name; + tmp_name.Printf ("[%s]", settings->GetInstanceName().AsCString()); + const ConstString instance_name (tmp_name.GetData()); + const SettingEntry *entry = GetInstanceEntry (var_name); + settings->UpdateInstanceSettingsVariable (var_name, index_value, value, instance_name, *entry, op, err, false); + + } +} + +void +UserSettingsController::RegisterInstanceSettings (InstanceSettings *instance_settings) +{ + Mutex::Locker locker (m_live_settings_mutex); + StreamString tmp_name; + tmp_name.Printf ("[%s]", instance_settings->GetInstanceName().AsCString()); + const ConstString instance_name (tmp_name.GetData()); + std::string instance_name_str (instance_name.AsCString()); + if (instance_name_str.compare (InstanceSettings::GetDefaultName().AsCString()) != 0) + m_live_settings[instance_name_str] = instance_settings; +} + +void +UserSettingsController::UnregisterInstanceSettings (InstanceSettings *instance) +{ + Mutex::Locker locker (m_live_settings_mutex); + StreamString tmp_name; + tmp_name.Printf ("[%s]", instance->GetInstanceName().AsCString()); + std::string instance_name (tmp_name.GetData()); + + std::map <std::string, InstanceSettings *>::iterator pos; + + pos = m_live_settings.find (instance_name); + if (pos != m_live_settings.end()) + m_live_settings.erase (pos); +} + +void +UserSettingsController::CreateSettingsVector (const SettingEntry *table, + bool global) +{ + int i = 0; + while (table[i].var_name != NULL) + { + const SettingEntry &table_entry = table[i]; + ConstString const_var_name (table_entry.var_name); + SettingEntry new_entry; + + new_entry = table_entry; + new_entry.var_name = const_var_name.AsCString(); + + if (global) + m_settings.global_settings.push_back (new_entry); + else + m_settings.instance_settings.push_back (new_entry); + + ++i; + } +} + +//---------------------------------------------------------------------- +// UserSettingsController static methods +//---------------------------------------------------------------------- + +int +FindMaxNameLength (std::vector<SettingEntry> table) +{ + int max_length = 1; + + for (int i = 0; i < table.size(); ++i) + { + int len = strlen (table[i].var_name); + if (len > max_length) + max_length = len; + } + + return max_length; +} + +const char * +UserSettingsController::GetTypeString (lldb::SettableVariableType var_type) +{ + switch (var_type) + { + case lldb::eSetVarTypeInt: + return "int"; + case lldb::eSetVarTypeBool: + return "boolean"; + case lldb::eSetVarTypeString: + return "string"; + case lldb::eSetVarTypeArray: + return "array"; + case lldb::eSetVarTypeDictionary: + return "dictionary"; + case lldb::eSetVarTypeEnum: + return "enum"; + case lldb::eSetVarTypeNone: + return "no type"; + } + + return ""; +} + +void +UserSettingsController::PrintEnumValues (const lldb::OptionEnumValueElement *enum_values, Stream &str) +{ + int i = 0; + while (enum_values[i].string_value != NULL) + { + str.Printf ("%s ", enum_values[i].string_value); + ++i; + } + +} + +void +UserSettingsController::FindAllSettingsDescriptions (CommandInterpreter &interpreter, + lldb::UserSettingsControllerSP root, + std::string ¤t_prefix, + StreamString &result_stream, + Error &err) +{ + // Write out current prefix line. + StreamString prefix_line; + StreamString description; + uint32_t max_len; + int num_entries = root->m_settings.global_settings.size(); + + max_len = FindMaxNameLength (root->m_settings.global_settings); + + if (! current_prefix.empty()) + result_stream.Printf ("\n'%s' variables:\n\n", current_prefix.c_str()); + else + result_stream.Printf ("\nTop level variables:\n\n"); + + if (num_entries > 0) + { + // Write out all "global" variables. + for (int i = 0; i < num_entries; ++i) + { + SettingEntry entry = root->m_settings.global_settings[i]; + description.Clear(); + if (entry.var_type == lldb::eSetVarTypeEnum) + { + StreamString enum_values_str; + UserSettingsController::PrintEnumValues (entry.enum_values, enum_values_str); + description.Printf ("[static, enum] %s. Valid values: {%s} (default: '%s')", entry.description, + enum_values_str.GetData(), entry.enum_values[0].string_value); + } + else if (entry.default_value != NULL) + description.Printf ("[static, %s] %s (default: '%s')", GetTypeString (entry.var_type), + entry.description, entry.default_value); + + else + description.Printf ("[static, %s] %s (default: '')", GetTypeString (entry.var_type), + entry.description); + interpreter.OutputFormattedHelpText (result_stream, entry.var_name, "--", description.GetData(), + max_len); + } + } + + num_entries = root->m_settings.instance_settings.size(); + max_len = FindMaxNameLength (root->m_settings.instance_settings); + + if (num_entries > 0) + { + // Write out all instance variables. + for (int i = 0; i < num_entries; ++i) + { + SettingEntry entry = root->m_settings.instance_settings[i]; + description.Clear(); + if (entry.var_type == lldb::eSetVarTypeEnum) + { + StreamString enum_values_str; + UserSettingsController::PrintEnumValues (entry.enum_values, enum_values_str); + description.Printf ("[instance, enum] %s. Valid values: {%s} (default: '%s')", entry.description, + enum_values_str.GetData(), entry.enum_values[0].string_value); + } + else if (entry.default_value != NULL) + description.Printf ("[instance, %s] %s (default: '%s')", GetTypeString (entry.var_type), + entry.description, entry.default_value); + else + description.Printf ("[instance, %s] %s (default: '')", GetTypeString (entry.var_type), + entry.description); + interpreter.OutputFormattedHelpText (result_stream, entry.var_name, "--", description.GetData(), + max_len); + } + + } + + // Now, recurse across all children. + int num_children = root->GetNumChildren(); + for (int i = 0; i < num_children; ++i) + { + lldb::UserSettingsControllerSP child = root->GetChildAtIndex (i); + + if (child) + { + ConstString child_prefix = child->GetLevelName(); + StreamString new_prefix; + if (! current_prefix.empty() ) // May need to see if size() > 0 + new_prefix.Printf ("%s.%s", current_prefix.c_str(), child_prefix.AsCString()); + else + new_prefix.Printf ("%s", child_prefix.AsCString()); + std::string new_prefix_str = new_prefix.GetData(); + UserSettingsController::FindAllSettingsDescriptions (interpreter, child, new_prefix_str, result_stream, + err); + } + } +} + +void +UserSettingsController::GetAllVariableValues (CommandInterpreter &interpreter, + lldb::UserSettingsControllerSP root, + std::string ¤t_prefix, + StreamString &result_stream, + Error &err) +{ + StreamString description; + int num_entries = root->m_settings.global_settings.size(); + lldb::SettableVariableType var_type; + + + for (int i = 0; i < num_entries; ++i) + { + StreamString full_var_name; + SettingEntry entry = root->m_settings.global_settings[i]; + if (! current_prefix.empty()) // May need to see if size() > 0 + full_var_name.Printf ("%s.%s", current_prefix.c_str(), entry.var_name); + else + full_var_name.Printf ("%s", entry.var_name); + StringList value = root->GetVariable (full_var_name.GetData(), var_type); + description.Clear(); + if (value.GetSize() == 1) + description.Printf ("%s (%s) = %s", full_var_name.GetData(), GetTypeString (entry.var_type), + value.GetStringAtIndex (0)); + else + { + description.Printf ("%s (%s) = ", full_var_name.GetData(), GetTypeString (entry.var_type)); + for (int j = 0; j < value.GetSize(); ++j) + description.Printf ("%s ", value.GetStringAtIndex (j)); + } + + result_stream.Printf ("%s\n", description.GetData()); + } + + root->GetAllInstanceVariableValues (interpreter, result_stream); + root->GetAllPendingSettingValues (result_stream); + root->GetAllDefaultSettingValues (result_stream); + + + // Now, recurse across all children. + int num_children = root->GetNumChildren(); + for (int i = 0; i < num_children; ++i) + { + lldb::UserSettingsControllerSP child = root->GetChildAtIndex (i); + + if (child) + { + ConstString child_prefix = child->GetLevelName(); + StreamString new_prefix; + if (! current_prefix.empty()) // May need to see if size() > 0 + new_prefix.Printf ("%s.%s", current_prefix.c_str(), child_prefix.AsCString()); + else + new_prefix.Printf ("%s", child_prefix.AsCString()); + std::string new_prefix_str = new_prefix.GetData(); + UserSettingsController::GetAllVariableValues (interpreter, child, new_prefix_str, result_stream, + err); + } + } + +} + +Args +UserSettingsController::BreakNameIntoPieces (const char *full_dot_name) +{ + Args return_value; + std::string name_string (full_dot_name); + bool done = false; + + std::string piece; + std::string remainder (full_dot_name); + + while (!done) + { + size_t idx = remainder.find_first_of ('.'); + piece = remainder.substr (0, idx); + return_value.AppendArgument (piece.c_str()); + if (idx != std::string::npos) + remainder = remainder.substr (idx+1); + else + done = true; + } + + return return_value; +} + +bool +UserSettingsController::IsLiveInstance (const std::string &instance_name) +{ + std::map<std::string, InstanceSettings *>::iterator pos; + + pos = m_live_settings.find (instance_name); + if (pos != m_live_settings.end()) + return true; + + return false; +} + +int +UserSettingsController::CompleteSettingsValue (lldb::UserSettingsControllerSP root_settings, + const char *full_dot_name, + const char *partial_value, + bool &word_complete, + StringList &matches) +{ + Args names = UserSettingsController::BreakNameIntoPieces (full_dot_name); + int num_pieces = names.GetArgumentCount(); + word_complete = true; + + ConstString root_level = root_settings->GetLevelName(); + int num_extra_levels = num_pieces - 2; + if ((num_extra_levels > 0) + && root_level.GetLength() > 0) + { + ConstString current_level (names.GetArgumentAtIndex (0)); + if (current_level == root_level) + { + names.Shift(); + --num_extra_levels; + } + else + return 0; + } + + for (int i = 0; i < num_extra_levels; ++i) + { + ConstString child_level (names.GetArgumentAtIndex (0)); + bool found = false; + int num_children = root_settings->GetNumChildren(); + for (int j = 0; j < num_children && !found; ++j) + { + if (root_settings->GetChildAtIndex (j)->GetLevelName() == child_level) + { + found = true; + root_settings = root_settings->GetChildAtIndex (j); + names.Shift(); + } + } + if (!found) + return 0; + } + + if (names.GetArgumentCount() != 2) + return 0; + + std::string next_name (names.GetArgumentAtIndex (0)); + int len = next_name.length(); + names.Shift(); + + if ((next_name[0] == '[') && (next_name[len-1] == ']')) + { + // 'next_name' is instance name. Instance names are irrelevent here. + } + else + { + // 'next_name' is child name. + bool found = false; + int num_children = root_settings->GetNumChildren(); + ConstString child_level (next_name.c_str()); + for (int j = 0; j < num_children && !found; ++j) + { + if (root_settings->GetChildAtIndex (j)->GetLevelName() == child_level) + { + found = true; + root_settings = root_settings->GetChildAtIndex (j); + } + } + if (!found) + return 0; + } + + ConstString var_name (names.GetArgumentAtIndex(0)); + const SettingEntry *entry = root_settings->GetGlobalEntry (var_name); + if (entry == NULL) + entry = root_settings->GetInstanceEntry (var_name); + + if (entry == NULL) + return 0; + + if (entry->var_type == lldb::eSetVarTypeBool) + return UserSettingsController::BooleanMatches (partial_value, word_complete, matches); + else if (entry->var_type == lldb::eSetVarTypeEnum) + return UserSettingsController::EnumMatches (partial_value, entry->enum_values, word_complete, matches); + else + return 0; +} + +int +UserSettingsController::BooleanMatches (const char *partial_value, + bool &word_complete, + StringList &matches) +{ + static const std::string true_string ("true"); + static const std::string false_string ("false"); + + if (partial_value == NULL) + { + matches.AppendString ("true"); + matches.AppendString ("false"); + } + else + { + int partial_len = strlen (partial_value); + + if ((partial_len <= true_string.length()) + && (true_string.find (partial_value) == 0)) + matches.AppendString ("true"); + else if ((partial_len <= false_string.length()) + && (false_string.find (partial_value) == 0)) + matches.AppendString ("false"); + } + + word_complete = false; + if (matches.GetSize() == 1) + word_complete = true; + + return matches.GetSize(); +} + +int +UserSettingsController::EnumMatches (const char *partial_value, + lldb::OptionEnumValueElement *enum_values, + bool &word_complete, + StringList &matches) +{ + int len = (partial_value != NULL) ? strlen (partial_value) : 0; + + int i = 0; + while (enum_values[i].string_value != NULL) + { + if (len == 0) + matches.AppendString (enum_values[i].string_value); + else + { + std::string tmp_value (enum_values[i].string_value); + if ((len <= tmp_value.length()) + && tmp_value.find (partial_value) == 0) + matches.AppendString (enum_values[i].string_value); + } + ++i; + } + + word_complete = false; + if (matches.GetSize() == 1) + word_complete = true; + + return matches.GetSize(); +} + +int +UserSettingsController::CompleteSettingsNames (lldb::UserSettingsControllerSP root_settings, + Args &partial_setting_name_pieces, + bool &word_complete, + StringList &matches) +{ + int num_matches = 0; + int num_name_pieces = partial_setting_name_pieces.GetArgumentCount(); + + if (num_name_pieces > 1) + { + // There are at least two pieces, perhaps with multiple level names preceding them. + // First traverse all the extra levels, until we have exactly two pieces left. + + int num_extra_levels = num_name_pieces - 2; + + // Deal with current level first. + + ConstString root_level = root_settings->GetLevelName(); + if ((num_extra_levels > 0) + && (root_level.GetLength() > 0)) + { + ConstString current_level (partial_setting_name_pieces.GetArgumentAtIndex (0)); + if (current_level == root_level) + { + partial_setting_name_pieces.Shift(); + --num_extra_levels; + } + else + return 0; // The current level did not match the name pieces; something is wrong, so return immediately + + } + + for (int i = 0; i < num_extra_levels; ++i) + { + ConstString child_level (partial_setting_name_pieces.GetArgumentAtIndex (0)); + bool found = false; + int num_children = root_settings->GetNumChildren(); + for (int j = 0; j < num_children && !found; ++j) + { + if (root_settings->GetChildAtIndex (j)->GetLevelName() == child_level) + { + found = true; + root_settings = root_settings->GetChildAtIndex (j); + partial_setting_name_pieces.Shift(); + } + } + if (! found) + { + return 0; // Unable to find a matching child level name; something is wrong, so return immediately. + } + } + + // Now there should be exactly two name pieces left. If not there is an error, so return immediately + + if (partial_setting_name_pieces.GetArgumentCount() != 2) + return 0; + + std::string next_name (partial_setting_name_pieces.GetArgumentAtIndex (0)); + int len = next_name.length(); + partial_setting_name_pieces.Shift(); + + if ((next_name[0] == '[') && (next_name[len-1] == ']')) + { + // 'next_name' is an instance name. The last name piece must be a non-empty partial match against an + // instance_name, assuming 'next_name' is valid. + + if (root_settings->IsLiveInstance (next_name)) + { + std::string complete_prefix; + root_settings->BuildParentPrefix (complete_prefix); + + num_matches = root_settings->InstanceVariableMatches(partial_setting_name_pieces.GetArgumentAtIndex(0), + complete_prefix, + next_name.c_str(), + matches); + word_complete = true; + if (num_matches > 1) + word_complete = false; + + return num_matches; + } + else + return 0; // Invalid instance_name + } + else + { + // 'next_name' must be a child name. Find the correct child and pass the remaining piece to be resolved. + bool found = false; + int num_children = root_settings->GetNumChildren(); + ConstString child_level (next_name.c_str()); + for (int i = 0; i < num_children; ++i) + { + if (root_settings->GetChildAtIndex (i)->GetLevelName() == child_level) + { + found = true; + return UserSettingsController::CompleteSettingsNames (root_settings->GetChildAtIndex (i), + partial_setting_name_pieces, + word_complete, matches); + } + } + if (!found) + return 0; + } + } + else if (num_name_pieces == 1) + { + std::string complete_prefix; + root_settings->BuildParentPrefix (complete_prefix); + + word_complete = true; + std::string name (partial_setting_name_pieces.GetArgumentAtIndex (0)); + + if (name[0] == '[') + { + // It's a partial instance name. + + num_matches = root_settings->LiveInstanceMatches (name.c_str(), complete_prefix, word_complete, matches); + } + else + { + // It could be anything *except* an instance name... + + num_matches = root_settings->GlobalVariableMatches (name.c_str(), complete_prefix, matches); + num_matches += root_settings->InstanceVariableMatches (name.c_str(), complete_prefix, NULL, matches); + num_matches += root_settings->ChildMatches (name.c_str(), complete_prefix, word_complete, matches); + } + + if (num_matches > 1) + word_complete = false; + + return num_matches; + } + else + { + // We have a user settings controller with a blank partial string. Return everything possible at this level. + + std::string complete_prefix; + root_settings->BuildParentPrefix (complete_prefix); + num_matches = root_settings->GlobalVariableMatches (NULL, complete_prefix, matches); + num_matches += root_settings->InstanceVariableMatches (NULL, complete_prefix, NULL, matches); + num_matches += root_settings->LiveInstanceMatches (NULL, complete_prefix, word_complete, matches); + num_matches += root_settings->ChildMatches (NULL, complete_prefix, word_complete, matches); + word_complete = false; + return num_matches; + } + + return num_matches; +} + +int +UserSettingsController::GlobalVariableMatches (const char *partial_name, + const std::string &complete_prefix, + StringList &matches) +{ + int partial_len = (partial_name != NULL) ? strlen (partial_name) : 0; + int num_matches = 0; + + for (size_t i = 0; i < m_settings.global_settings.size(); ++i) + { + SettingEntry &entry = m_settings.global_settings[i]; + std::string var_name (entry.var_name); + if ((partial_len == 0) + || ((partial_len <= var_name.length()) + && (var_name.find (partial_name) == 0))) + { + StreamString match_name; + if (complete_prefix.length() > 0) + { + match_name.Printf ("%s.%s", complete_prefix.c_str(), var_name.c_str()); + matches.AppendString (match_name.GetData()); + } + else + matches.AppendString (var_name.c_str()); + ++num_matches; + } + } + return num_matches; +} + +int +UserSettingsController::InstanceVariableMatches (const char *partial_name, + const std::string &complete_prefix, + const char *instance_name, + StringList &matches) +{ + int partial_len = (partial_name != NULL) ? strlen (partial_name) : 0; + int num_matches = 0; + + for (size_t i = 0; i < m_settings.instance_settings.size(); ++i) + { + SettingEntry &entry = m_settings.instance_settings[i]; + std::string var_name (entry.var_name); + if ((partial_len == 0) + || ((partial_len <= var_name.length()) + && (var_name.find (partial_name) == 0))) + { + StreamString match_name; + if (complete_prefix.length() > 0) + { + if (instance_name != NULL) + match_name.Printf ("%s.%s.%s", complete_prefix.c_str(), instance_name, var_name.c_str()); + else + match_name.Printf ("%s.%s", complete_prefix.c_str(), var_name.c_str()); + + matches.AppendString (match_name.GetData()); + } + else + { + if (instance_name != NULL) + { + match_name.Printf ("%s.%s", instance_name, var_name.c_str()); + matches.AppendString (match_name.GetData()); + } + else + matches.AppendString (var_name.c_str()); + } + ++num_matches; + } + } + return num_matches; +} + +int +UserSettingsController::LiveInstanceMatches (const char *partial_name, + const std::string &complete_prefix, + bool &word_complete, + StringList &matches) +{ + int partial_len = (partial_name != NULL) ? strlen (partial_name) : 0; + int num_matches = 0; + + std::map<std::string, InstanceSettings*>::iterator pos; + for (pos = m_live_settings.begin(); pos != m_live_settings.end(); ++pos) + { + std::string instance_name = pos->first; + if ((partial_len == 0) + || ((partial_len <= instance_name.length()) + && (instance_name.find (partial_name) == 0))) + { + StreamString match_name; + if (complete_prefix.length() > 0) + match_name.Printf ("%s.%s.", complete_prefix.c_str(), instance_name.c_str()); + else + match_name.Printf ("%s.", instance_name.c_str()); + matches.AppendString (match_name.GetData()); + ++num_matches; + } + } + + if (num_matches > 0) + word_complete = false; + + return num_matches; +} + +int +UserSettingsController::ChildMatches (const char *partial_name, + const std::string &complete_prefix, + bool &word_complete, + StringList &matches) +{ + int partial_len = (partial_name != NULL) ? strlen (partial_name) : 0; + int num_children = GetNumChildren(); + int num_matches = 0; + for (int i = 0; i < num_children; ++i) + { + std::string child_name (GetChildAtIndex(i)->GetLevelName().AsCString()); + StreamString match_name; + if ((partial_len == 0) + || ((partial_len <= child_name.length()) + && (child_name.find (partial_name) == 0))) + { + if (complete_prefix.length() > 0) + match_name.Printf ("%s.%s.", complete_prefix.c_str(), child_name.c_str()); + else + match_name.Printf ("%s.", child_name.c_str()); + matches.AppendString (match_name.GetData()); + ++num_matches; + } + } + + if (num_matches > 0) + word_complete = false; + + return num_matches; +} + +void +UserSettingsController::VerifyOperationForType (lldb::SettableVariableType var_type, + lldb::VarSetOperationType op, + const ConstString &var_name, + Error &err) +{ + if (op == lldb::eVarSetOperationAssign) + return; + + + if (op == lldb::eVarSetOperationInvalid) + { + err.SetErrorString ("Invalid 'settings ' subcommand operation.\n"); + return; + } + + switch (op) + { + case lldb::eVarSetOperationInsertBefore: + case lldb::eVarSetOperationInsertAfter: + if (var_type != lldb::eSetVarTypeArray) + err.SetErrorString ("Invalid operation: This operation can only be performed on array variables.\n"); + break; + case lldb::eVarSetOperationReplace: + case lldb::eVarSetOperationRemove: + if ((var_type != lldb::eSetVarTypeArray) + && (var_type != lldb::eSetVarTypeDictionary)) + err.SetErrorString ("Invalid operation: This operation can only be performed on array or dictionary" + " variables.\n"); + break; + case lldb::eVarSetOperationAppend: + case lldb::eVarSetOperationClear: + if ((var_type != lldb::eSetVarTypeArray) + && (var_type != lldb::eSetVarTypeDictionary) + && (var_type != lldb::eSetVarTypeString)) + err.SetErrorString ("Invalid operation: This operation can only be performed on array, dictionary " + "or string variables.\n"); + break; + default: + break; + } + + return; +} + +void +UserSettingsController::UpdateStringVariable (lldb::VarSetOperationType op, + std::string &string_var, + const char *new_value, + Error &err) +{ + if (op == lldb::eVarSetOperationAssign) + string_var = new_value; + else if (op == lldb::eVarSetOperationAppend) + string_var.append (new_value); + else if (op == lldb::eVarSetOperationClear) + string_var.clear(); + else + err.SetErrorString ("Unrecognized operation. Cannot update value.\n"); +} + +void +UserSettingsController::UpdateBooleanVariable (lldb::VarSetOperationType op, + bool &bool_var, + const char *new_value, + Error &err) +{ + if (op != lldb::eVarSetOperationAssign) + err.SetErrorString ("Invalid operation for Boolean variable. Cannot update value.\n"); + + + if ((new_value == NULL) + || (new_value[0] == '\0')) + err.SetErrorString ("Invalid value. Cannot perform update.\n"); + + std::string bool_val_str (new_value); + + std::transform (bool_val_str.begin(), bool_val_str.end(), bool_val_str.begin(), ::tolower); + + if (bool_val_str == "true") + bool_var = true; + else if (bool_val_str == "false") + bool_var = false; +} + +void +UserSettingsController::UpdateStringArrayVariable (lldb::VarSetOperationType op, + const char *index_value, + Args &array_var, + const char *new_value, + Error &err) +{ + int index = -1; + bool valid_index = true; + + if (index_value != NULL) + { + for (int i = 0; i < strlen(index_value); ++i) + if (!isdigit (index_value[i])) + { + valid_index = false; + err.SetErrorStringWithFormat ("'%s' is not a valid integer index. Cannot update array value.\n", + index_value); + } + + if (valid_index) + index = atoi (index_value); + + if (index < 0 + || index >= array_var.GetArgumentCount()) + { + valid_index = false; + err.SetErrorStringWithFormat ("%d is outside the bounds of the specified array variable. " + "Cannot update array value.\n", index); + } + } + + switch (op) + { + case lldb::eVarSetOperationAssign: + array_var.SetCommandString (new_value); + break; + case lldb::eVarSetOperationReplace: + { + if (valid_index) + array_var.ReplaceArgumentAtIndex (index, new_value); + break; + } + case lldb::eVarSetOperationInsertBefore: + case lldb::eVarSetOperationInsertAfter: + { + if (valid_index) + { + Args new_array (new_value); + if (op == lldb::eVarSetOperationInsertAfter) + ++index; + for (int i = 0; i < new_array.GetArgumentCount(); ++i) + array_var.InsertArgumentAtIndex (index, new_array.GetArgumentAtIndex (i)); + } + break; + } + case lldb::eVarSetOperationRemove: + { + if (valid_index) + array_var.DeleteArgumentAtIndex (index); + break; + } + case lldb::eVarSetOperationAppend: + { + Args new_array (new_value); + array_var.AppendArguments (new_array); + break; + } + case lldb::eVarSetOperationClear: + array_var.Clear(); + break; + default: + err.SetErrorString ("Unrecognized operation. Cannot update value.\n"); + break; + } +} + +void +UserSettingsController::UpdateDictionaryVariable (lldb::VarSetOperationType op, + const char *index_value, + std::map<std::string, std::string> &dictionary, + const char *new_value, + Error &err) +{ + switch (op) + { + case lldb::eVarSetOperationReplace: + if (index_value != NULL) + { + std::string key (index_value); + std::map<std::string, std::string>::iterator pos; + + pos = dictionary.find (key); + if (pos != dictionary.end()) + dictionary[key] = new_value; + else + err.SetErrorStringWithFormat ("'%s' is not an existing key; cannot replace value.\n", index_value); + } + else + err.SetErrorString ("'settings replace' requires a key for dictionary variables. No key supplied.\n"); + break; + case lldb::eVarSetOperationRemove: + if (index_value != NULL) + { + std::string key (index_value); + dictionary.erase (key); + } + else + err.SetErrorString ("'settings remove' requires a key for dictionary variables. No key supplied.\n"); + break; + case lldb::eVarSetOperationClear: + dictionary.clear (); + break; + case lldb::eVarSetOperationAppend: + case lldb::eVarSetOperationAssign: + { + Args args (new_value); + size_t num_args = args.GetArgumentCount(); + for (size_t i = 0; i < num_args; ++i) + { + std::string tmp_arg = args.GetArgumentAtIndex (i); + size_t eq_sign = tmp_arg.find ('='); + if (eq_sign != std::string::npos) + { + if (eq_sign > 4) + { + std::string tmp_key = tmp_arg.substr (0, eq_sign); + std::string real_value = tmp_arg.substr (eq_sign+1); + if ((tmp_key[0] == '[') + && (tmp_key[1] == '"') + && (tmp_key[eq_sign-2] == '"') + && (tmp_key[eq_sign-1] == ']')) + { + std::string real_key = tmp_key.substr (2, eq_sign-4); + dictionary[real_key] = real_value; + } + else + err.SetErrorString ("Invalid key format for dictionary assignment. " + "Expected '[\"<key>\"]'\n"); + } + else + err.SetErrorString ("Invalid key format for dictionary assignment. " + "Expected '[\"<key>\"]'\n"); + } + else + err.SetErrorString ("Invalid format for dictionary value. Expected '[\"<key>\"]=<value>'\n"); + } + } + break; + case lldb::eVarSetOperationInsertBefore: + case lldb::eVarSetOperationInsertAfter: + err.SetErrorString ("Specified operation cannot be performed on dictionary variables.\n"); + break; + default: + err.SetErrorString ("Unrecognized operation.\n"); + break; + } +} + +const char * +UserSettingsController::EnumToString (const lldb::OptionEnumValueElement *enum_values, + int value) +{ + int i = 0; + while (enum_values[i].string_value != NULL) + { + if (enum_values[i].value == value) + return enum_values[i].string_value; + ++i; + } + + return "Invalid enumeration value"; +} + + +void +UserSettingsController::UpdateEnumVariable (lldb::OptionEnumValueElement *enum_values, + int *enum_var, + const char *new_value, + Error &err) +{ + bool found_one; + + *enum_var = Args::StringToOptionEnum (new_value, enum_values, enum_values[0].value, &found_one); + + if (!found_one) + err.SetErrorString ("Invalid enumeration value; cannot update variable.\n"); +} + +//---------------------------------------------------------------------- +// class InstanceSettings +//---------------------------------------------------------------------- + +InstanceSettings::InstanceSettings (UserSettingsController &owner, const char *instance_name) : + m_owner (owner), + m_instance_name (instance_name) +{ + if (m_instance_name != InstanceSettings::GetDefaultName()) + m_owner.RegisterInstanceSettings (this); +} + +InstanceSettings::~InstanceSettings () +{ + if (m_instance_name != InstanceSettings::GetDefaultName()) + m_owner.UnregisterInstanceSettings (this); +} + +const ConstString & +InstanceSettings::GetDefaultName () +{ + static const ConstString g_default_settings_name ("[DEFAULT]"); + + return g_default_settings_name; +} |