openMSX
SettingsManager.cc
Go to the documentation of this file.
1 #include "SettingsManager.hh"
3 #include "TclObject.hh"
4 #include "CommandException.hh"
5 #include "XMLElement.hh"
6 #include "outer.hh"
7 #include "vla.hh"
8 #include <cassert>
9 #include <cstring>
10 
11 using std::string;
12 using std::vector;
13 
14 namespace openmsx {
15 
16 // SettingsManager implementation:
17 
19  : settingInfo (commandController.getOpenMSXInfoCommand())
20  , setCompleter (commandController)
21  , incrCompleter (commandController, *this, "incr")
22  , unsetCompleter(commandController, *this, "unset")
23 {
24 }
25 
27 {
28  assert(settings.empty());
29 }
30 
32 {
33  assert(!settings.contains(setting.getFullNameObj()));
34  settings.emplace_noDuplicateCheck(&setting);
35 }
36 
38 {
39  const auto& name = setting.getFullNameObj();
40  assert(settings.contains(name));
41  settings.erase(name);
42 }
43 
45 {
46  auto it = settings.find(name);
47  return (it != end(settings)) ? *it : nullptr;
48 }
49 
51 {
52  auto size = prefix.size() + baseName.size();
53  VLA(char, fullname, size);
54  memcpy(&fullname[0], prefix .data(), prefix .size());
55  memcpy(&fullname[prefix.size()], baseName.data(), baseName.size());
56  return findSetting(string_ref(fullname, size));
57 }
58 
59 // Helper functions for setting commands
60 
61 BaseSetting& SettingsManager::getByName(string_ref cmd, string_ref name) const
62 {
63  if (auto* setting = findSetting(name)) {
64  return *setting;
65  }
66  throw CommandException(cmd + ": " + name + ": no such setting");
67 }
68 
69 vector<string> SettingsManager::getTabSettingNames() const
70 {
71  vector<string> result;
72  result.reserve(settings.size() * 2);
73  for (auto* s : settings) {
74  string_ref name = s->getFullName();
75  result.push_back(name.str());
76  if (name.starts_with("::")) {
77  result.push_back(name.substr(2).str());
78  } else {
79  result.push_back("::" + name);
80  }
81  }
82  return result;
83 }
84 
86 {
87  // restore default values
88  for (auto* s : settings) {
89  if (s->needLoadSave()) {
90  s->setValue(s->getRestoreValue());
91  }
92  }
93 
94  // load new values
95  auto* settingsElem = config.findChild("settings");
96  if (!settingsElem) return;
97  for (auto* s : settings) {
98  if (!s->needLoadSave()) continue;
99  if (auto* elem = settingsElem->findChildWithAttribute(
100  "setting", "id", s->getFullName())) {
101  try {
102  s->setValue(TclObject(elem->getData()));
103  } catch (MSXException&) {
104  // ignore, keep default value
105  }
106  }
107  }
108 }
109 
110 
111 // class SettingInfo
112 
113 SettingsManager::SettingInfo::SettingInfo(InfoCommand& openMSXInfoCommand)
114  : InfoTopic(openMSXInfoCommand, "setting")
115 {
116 }
117 
118 void SettingsManager::SettingInfo::execute(
119  array_ref<TclObject> tokens, TclObject& result) const
120 {
121  auto& manager = OUTER(SettingsManager, settingInfo);
122  switch (tokens.size()) {
123  case 2:
124  for (auto* p : manager.settings) {
125  result.addListElement(p->getFullNameObj());
126  }
127  break;
128  case 3: {
129  const auto& settingName = tokens[2].getString();
130  auto it = manager.settings.find(settingName);
131  if (it == end(manager.settings)) {
132  throw CommandException("No such setting: " + settingName);
133  }
134  (*it)->info(result);
135  break;
136  }
137  default:
138  throw CommandException("Too many parameters.");
139  }
140 }
141 
142 string SettingsManager::SettingInfo::help(const vector<string>& /*tokens*/) const
143 {
144  return "openmsx_info setting : "
145  "returns list of all settings\n"
146  "openmsx_info setting <name> : "
147  "returns info on a specific setting\n";
148 }
149 
150 void SettingsManager::SettingInfo::tabCompletion(vector<string>& tokens) const
151 {
152  if (tokens.size() == 3) {
153  // complete setting name
154  auto& manager = OUTER(SettingsManager, settingInfo);
155  completeString(tokens, manager.getTabSettingNames());
156  }
157 }
158 
159 
160 // class SetCompleter
161 
162 SettingsManager::SetCompleter::SetCompleter(
163  CommandController& commandController_)
164  : CommandCompleter(commandController_, "set")
165 {
166 }
167 
168 string SettingsManager::SetCompleter::help(const vector<string>& tokens) const
169 {
170  if (tokens.size() == 2) {
171  auto& manager = OUTER(SettingsManager, setCompleter);
172  return manager.getByName("set", tokens[1]).getDescription().str();
173  }
174  return "Set or query the value of a openMSX setting or Tcl variable\n"
175  " set <setting> shows current value\n"
176  " set <setting> <value> set a new value\n"
177  "Use 'help set <setting>' to get more info on a specific\n"
178  "openMSX setting.\n";
179 }
180 
181 void SettingsManager::SetCompleter::tabCompletion(vector<string>& tokens) const
182 {
183  auto& manager = OUTER(SettingsManager, setCompleter);
184  switch (tokens.size()) {
185  case 2: {
186  // complete setting name
187  completeString(tokens, manager.getTabSettingNames(), false); // case insensitive
188  break;
189  }
190  case 3: {
191  // complete setting value
192  auto it = manager.settings.find(tokens[1]);
193  if (it != end(manager.settings)) {
194  (*it)->tabCompletion(tokens);
195  }
196  break;
197  }
198  }
199 }
200 
201 
202 // class SettingCompleter
203 
204 SettingsManager::SettingCompleter::SettingCompleter(
205  CommandController& commandController_, SettingsManager& manager_,
206  const string& name_)
207  : CommandCompleter(commandController_, name_)
208  , manager(manager_)
209 {
210 }
211 
212 string SettingsManager::SettingCompleter::help(const vector<string>& /*tokens*/) const
213 {
214  return ""; // TODO
215 }
216 
217 void SettingsManager::SettingCompleter::tabCompletion(vector<string>& tokens) const
218 {
219  if (tokens.size() == 2) {
220  // complete setting name
221  completeString(tokens, manager.getTabSettingNames());
222  }
223 }
224 
225 } // namespace openmsx
string_ref::const_iterator end(const string_ref &x)
Definition: string_ref.hh:167
size_type size() const
Definition: array_ref.hh:61
std::string str() const
Definition: string_ref.cc:12
void unregisterSetting(BaseSetting &setting)
bool starts_with(string_ref x) const
Definition: string_ref.cc:116
This class implements a subset of the proposal for std::string_ref (proposed for the next c++ standar...
Definition: string_ref.hh:18
void loadSettings(const XMLElement &config)
const XMLElement * findChild(string_ref name) const
Definition: XMLElement.cc:117
size_type size() const
Definition: string_ref.hh:55
const char * data() const
Definition: string_ref.hh:68
This class implements a subset of the proposal for std::array_ref (proposed for the next c++ standard...
Definition: array_ref.hh:19
void registerSetting(BaseSetting &setting)
BaseSetting * findSetting(string_ref name) const
Find the setting with given name.
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
uint8_t * data()
size_t size() const
string_ref substr(size_type pos, size_type n=npos) const
Definition: string_ref.cc:32
SettingsManager(const SettingsManager &)=delete
#define OUTER(type, member)
Definition: outer.hh:38
#define VLA(TYPE, NAME, LENGTH)
Definition: vla.hh:10
const TclObject & getFullNameObj() const
Get the name of this setting.
Definition: Setting.hh:31