1 //====-- UserSettingsController.cpp ------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include <string.h>
11 #include <algorithm>
12 
13 #include "lldb/Core/UserSettingsController.h"
14 #include "lldb/Core/Error.h"
15 #include "lldb/Core/RegularExpression.h"
16 #include "lldb/Core/Stream.h"
17 #include "lldb/Core/StreamString.h"
18 #include "lldb/Interpreter/CommandInterpreter.h"
19 
20 using namespace lldb;
21 using namespace lldb_private;
22 
23 static void
24 DumpSettingEntry (CommandInterpreter &interpreter,
25                   Stream &strm,
26                   const uint32_t max_len,
27                   const SettingEntry &entry)
28 {
29     StreamString description;
30 
31     if (entry.description)
32         description.Printf ("%s", entry.description);
33 
34     if (entry.default_value && entry.default_value[0])
35         description.Printf (" (default: %s)", entry.default_value);
36 
37     interpreter.OutputFormattedHelpText (strm,
38                                          entry.var_name,
39                                          "--",
40                                          description.GetData(),
41                                          max_len);
42 
43     if (entry.enum_values && entry.enum_values[0].string_value)
44     {
45         interpreter.OutputFormattedHelpText (strm,
46                                              "",
47                                              "  ",
48                                              "Enumeration values:",
49                                              max_len);
50         for (uint32_t enum_idx=0; entry.enum_values[enum_idx].string_value != NULL; ++enum_idx)
51         {
52             description.Clear();
53             if (entry.enum_values[enum_idx].usage)
54                 description.Printf ("%s = %s",
55                                     entry.enum_values[enum_idx].string_value,
56                                     entry.enum_values[enum_idx].usage);
57             else
58                 description.Printf ("%s", entry.enum_values[enum_idx].string_value);
59             interpreter.OutputFormattedHelpText (strm,
60                                                  "",
61                                                  "  ",
62                                                  description.GetData(),
63                                                  max_len);
64         }
65     }
66 }
67 
68 UserSettingsController::UserSettingsController (const char *level_name,
69                                                 const UserSettingsControllerSP &parent) :
70     m_default_settings (),
71     m_settings (),
72     m_children (),
73     m_pending_settings (),
74     m_live_settings (),
75     m_children_mutex (Mutex::eMutexTypeNormal),
76     m_pending_settings_mutex (Mutex::eMutexTypeRecursive),
77     m_live_settings_mutex (Mutex::eMutexTypeRecursive)
78 {
79     m_settings.parent = parent;
80     m_settings.level_name.SetCString (level_name);
81 }
82 
83 UserSettingsController::~UserSettingsController ()
84 {
85     Mutex::Locker locker (m_live_settings_mutex);
86     m_live_settings.clear();
87 }
88 
89 bool
90 UserSettingsController::SetGlobalVariable
91 (
92     const ConstString &var_name,
93     const char *index_value,
94     const char *value,
95     const SettingEntry &entry,
96     const VarSetOperationType op,
97     Error &err
98 )
99 {
100     err.SetErrorString ("UserSettingsController has no global settings");
101     return false;
102 }
103 
104 bool
105 UserSettingsController::GetGlobalVariable
106 (
107     const ConstString &var_name,
108     StringList &value,
109     Error &err
110 )
111 {
112     return false;
113 }
114 
115 bool
116 UserSettingsController::InitializeSettingsController (UserSettingsControllerSP &controller_sp,
117                                                       SettingEntry *global_settings,
118                                                       SettingEntry *instance_settings)
119 {
120     const UserSettingsControllerSP &parent = controller_sp->GetParent ();
121     if (parent)
122         parent->RegisterChild (controller_sp);
123 
124     controller_sp->CreateSettingsVector (global_settings, true);
125     controller_sp->CreateSettingsVector (instance_settings, false);
126 
127     controller_sp->InitializeGlobalVariables ();
128     controller_sp->CreateDefaultInstanceSettings ();
129 
130     return true;
131 }
132 
133 void
134 UserSettingsController::FinalizeSettingsController (UserSettingsControllerSP &controller_sp)
135 {
136     const UserSettingsControllerSP &parent = controller_sp->GetParent ();
137     if (parent)
138         parent->RemoveChild (controller_sp);
139 }
140 
141 void
142 UserSettingsController::InitializeGlobalVariables ()
143 {
144     int num_entries;
145     const char *prefix = GetLevelName().GetCString();
146 
147     num_entries = m_settings.global_settings.size();
148     for (int i = 0; i < num_entries; ++i)
149     {
150         const SettingEntry &entry = m_settings.global_settings[i];
151         if (entry.default_value != NULL)
152         {
153             StreamString full_name;
154             if (prefix[0] != '\0')
155                 full_name.Printf ("%s.%s", prefix, entry.var_name);
156             else
157                 full_name.Printf ("%s", entry.var_name);
158             SetVariable (full_name.GetData(), entry.default_value, eVarSetOperationAssign, false, "");
159         }
160     }
161 }
162 
163 const UserSettingsControllerSP &
164 UserSettingsController::GetParent ()
165 {
166     return m_settings.parent;
167 }
168 
169 void
170 UserSettingsController::RegisterChild (const UserSettingsControllerSP &child)
171 {
172     Mutex::Locker locker (m_children_mutex);
173 
174     // Verify child is not already in m_children.
175     size_t num_children = m_children.size();
176     bool found = false;
177     for (size_t i = 0; i < num_children; ++i)
178       {
179 	if (m_children[i].get() == child.get())
180     	    found = true;
181       }
182 
183     // Add child to m_children.
184     if (! found)
185         m_children.push_back (child);
186 }
187 
188 const ConstString &
189 UserSettingsController::GetLevelName ()
190 {
191     return m_settings.level_name;
192 }
193 
194 size_t
195 UserSettingsController::GetNumChildren ()
196 {
197     return m_children.size();
198 }
199 
200 const UserSettingsControllerSP
201 UserSettingsController::GetChildAtIndex (size_t index)
202 {
203     if (index < m_children.size())
204         return m_children[index];
205 
206     UserSettingsControllerSP dummy_value;
207 
208     return dummy_value;
209 }
210 
211 const SettingEntry *
212 UserSettingsController::GetGlobalEntry (const ConstString &var_name)
213 {
214 
215     for (int i = 0; i < m_settings.global_settings.size(); ++i)
216     {
217         const SettingEntry &entry = m_settings.global_settings[i];
218         ConstString entry_name (entry.var_name);
219         if (entry_name == var_name)
220             return &entry;
221     }
222 
223     return NULL;
224 }
225 
226 const SettingEntry *
227 UserSettingsController::GetInstanceEntry (const ConstString &const_var_name)
228 {
229 
230     for (int i = 0; i < m_settings.instance_settings.size(); ++i)
231     {
232         SettingEntry &entry = m_settings.instance_settings[i];
233         ConstString entry_name (entry.var_name);
234         if (entry_name == const_var_name)
235             return &entry;
236     }
237 
238     return NULL;
239 }
240 
241 void
242 UserSettingsController::BuildParentPrefix (std::string &parent_prefix)
243 {
244     UserSettingsControllerSP parent = GetParent();
245     if (parent.get() != NULL)
246     {
247         parent->BuildParentPrefix (parent_prefix);
248         if (parent_prefix.length() > 0)
249             parent_prefix.append (".");
250     }
251     parent_prefix.append (GetLevelName().GetCString());
252 }
253 
254 void
255 UserSettingsController::RemoveChild (const UserSettingsControllerSP &child)
256 {
257     Mutex::Locker locker (m_children_mutex);
258     std::vector<UserSettingsControllerSP>::iterator pos, end = m_children.end();
259 
260    for (pos = m_children.begin(); pos != end; ++pos)
261    {
262       UserSettingsControllerSP entry = *pos;
263       if (entry == child)
264       {
265           m_children.erase (pos);
266           break;
267       }
268    }
269 }
270 
271 Error
272 UserSettingsController::SetVariable (const char *full_dot_name,
273                                      const char *value,
274                                      const VarSetOperationType op,
275                                      const bool override,
276                                      const char *debugger_instance_name,
277                                      const char *index_value)
278 {
279     Error err;
280     ConstString const_var_name;
281     const ConstString &default_name = InstanceSettings::GetDefaultName();
282 
283     Args names;
284     if (full_dot_name )
285         names = UserSettingsController::BreakNameIntoPieces (full_dot_name);
286     int num_pieces = names.GetArgumentCount();
287 
288     if (num_pieces < 1)
289     {
290         err.SetErrorStringWithFormat ("'%s' is not a valid variable name; cannot assign value", full_dot_name);
291         return err;
292     }
293 
294     ConstString prefix (names.GetArgumentAtIndex (0));
295 
296     if ((prefix == m_settings.level_name)
297         || (m_settings.level_name.GetLength() == 0))
298     {
299 
300         if (prefix == m_settings.level_name)
301         {
302             names.Shift ();
303             num_pieces = names.GetArgumentCount();
304         }
305 
306         if (num_pieces == 0)
307         {
308             err.SetErrorString ("no variable name specified, cannot assign value");
309             return err;
310         }
311         else if (num_pieces == 1)
312         {
313 
314             // Must be one of the class-wide settings.
315 
316             const_var_name.SetCString (names.GetArgumentAtIndex (0));
317             const SettingEntry *entry = GetGlobalEntry (const_var_name);
318             if (entry)
319             {
320                 UserSettingsController::VerifyOperationForType (entry->var_type, op, const_var_name, err);
321 
322                 if (err.Fail())
323                     return err;
324 
325                 if ((value == NULL || value[0] == '\0')
326                     && (op == eVarSetOperationAssign))
327                 {
328                     if (entry->var_type != eSetVarTypeEnum)
329                         value = entry->default_value;
330                     else
331                         value = entry->enum_values[0].string_value;
332                 }
333                 SetGlobalVariable (const_var_name, index_value, value, *entry, op, err);
334             }
335             else
336             {
337                 // MIGHT be instance variable, to be for ALL instances.
338 
339                 entry = GetInstanceEntry (const_var_name);
340                 if (entry == NULL)
341                 {
342                     err.SetErrorStringWithFormat ("unable to find variable '%s.%s', cannot assign value",
343                                                   prefix.GetCString(), const_var_name.GetCString());
344                     return err;
345                 }
346                 else
347                 {
348                     UserSettingsController::VerifyOperationForType (entry->var_type, op, const_var_name, err);
349 
350                     if (err.Fail())
351                         return err;
352 
353                     if ((value == NULL || value[0] == '\0')
354                         && (op == eVarSetOperationAssign))
355                     {
356                         if (entry->var_type != eSetVarTypeEnum)
357                             value = entry->default_value;
358                         else
359                             value = entry->enum_values[0].string_value;
360                     }
361 
362                     if ((m_settings.level_name.GetLength() > 0)
363                         || strlen (debugger_instance_name) == 0)
364                       {
365                         // Set the default settings
366                         m_default_settings->UpdateInstanceSettingsVariable (const_var_name, index_value, value,
367                                                                             default_name, *entry, op, err, true);
368                       }
369                     else
370                       {
371                         // We're at the Debugger level; find the correct debugger instance and set those settings
372                         StreamString tmp_name;
373                         if (debugger_instance_name[0] != '[')
374                             tmp_name.Printf ("[%s]", debugger_instance_name);
375                         else
376                             tmp_name.Printf ("%s", debugger_instance_name);
377                         ConstString dbg_name (tmp_name.GetData());
378                         InstanceSettings *dbg_settings = FindSettingsForInstance (dbg_name);
379                         if (dbg_settings)
380                             dbg_settings->UpdateInstanceSettingsVariable (const_var_name, index_value, value, dbg_name,
381                                                                           *entry, op, err, false);
382                       }
383 
384                     if (override)
385                     {
386                         OverrideAllInstances (const_var_name, value, op, index_value, err);
387 
388                         // Update all pending records as well.
389 //                        std::map<std::string, InstanceSettingsSP>::iterator pos, end = m_pending_settings.end();
390 //                        for (pos = m_pending_settings.begin(); pos != end; end++)
391 //                        {
392 //                            const ConstString instance_name (pos->first.c_str());
393 //                            InstanceSettingsSP setting_sp = pos->second;
394 //                            setting_sp->UpdateInstanceSettingsVariable (const_var_name, index_value, value,
395 //                                                                        instance_name, *entry, op, err, true);
396 //                        }
397                     }
398                 }
399             }
400         }
401         else
402         {
403             // Either a child's setting or an instance setting.
404 
405             if (names.GetArgumentAtIndex(0)[0] == '[')
406             {
407                 // An instance setting.  Supposedly.
408 
409                 ConstString instance_name (names.GetArgumentAtIndex (0));
410 
411                 // First verify that there is only one more name.
412 
413                 names.Shift();
414 
415                 if (names.GetArgumentCount() != 1)
416                 {
417                     err.SetErrorStringWithFormat ("invalid variable name format '%s', cannot assign value",
418                                                   full_dot_name);
419                     return err;
420                 }
421 
422                 // Next verify that it is a valid instance setting name.
423 
424                 const_var_name.SetCString (names.GetArgumentAtIndex (0));
425                 const SettingEntry *entry = GetInstanceEntry (const_var_name);
426 
427                 if (entry == NULL)
428                 {
429                     err.SetErrorStringWithFormat ("unknown instance variable '%s', cannot assign value",
430                                                   const_var_name.GetCString());
431                     return err;
432                 }
433 
434                 UserSettingsController::VerifyOperationForType (entry->var_type, op, const_var_name, err);
435 
436                 if (err.Fail())
437                     return err;
438 
439                 if ((value == NULL || value[0] == '\0')
440                     && (op == eVarSetOperationAssign))
441                 {
442                     if (entry->var_type != eSetVarTypeEnum)
443                         value = entry->default_value;
444                     else
445                         value = entry->enum_values[0].string_value;
446                 }
447 
448                 // Now look for existing instance with given instance name; if not found, find or create pending
449                 // setting for instance with given name.
450 
451                 InstanceSettings *current_settings = FindSettingsForInstance (instance_name);
452 
453                 if (current_settings != NULL)
454                 {
455                     current_settings->UpdateInstanceSettingsVariable (const_var_name, index_value, value,
456                                                                       instance_name, *entry, op, err, false);
457 
458                 }
459                 else
460                 {
461                     // Instance does not currently exist; make or update a pending setting for it.
462                     InstanceSettingsSP current_settings_sp = PendingSettingsForInstance (instance_name);
463 
464                     // Now we have a settings record, update it appropriately.
465 
466                     current_settings_sp->UpdateInstanceSettingsVariable (const_var_name, index_value, value,
467                                                                          instance_name, *entry, op, err, true);
468 
469                     {   // Scope for mutex.
470                         Mutex::Locker locker (m_pending_settings_mutex);
471                         m_pending_settings[instance_name.GetCString()] = current_settings_sp;
472                     }
473 
474                     if (override)
475                     {
476                         OverrideAllInstances (const_var_name, value, op, index_value, err);
477 
478                         // Update all pending records as well.
479                         std::map<std::string, InstanceSettingsSP>::iterator pos;
480                         std::map<std::string, InstanceSettingsSP>::iterator end = m_pending_settings.end();
481                         for (pos = m_pending_settings.begin(); pos != end; end++)
482                         {
483                             const ConstString tmp_inst_name (pos->first.c_str());
484                             InstanceSettingsSP setting_sp = pos->second;
485                             setting_sp->UpdateInstanceSettingsVariable (const_var_name, index_value, value,
486                                                                         tmp_inst_name, *entry, op, err, true);
487                         }
488                     }
489                 }
490             }
491             else
492             {
493                 // A child setting.
494                 UserSettingsControllerSP child;
495                 ConstString child_prefix (names.GetArgumentAtIndex (0));
496                 int num_children = GetNumChildren();
497                 bool found = false;
498                 for (int i = 0; i < num_children && !found; ++i)
499                 {
500                     child = GetChildAtIndex (i);
501                     ConstString current_prefix = child->GetLevelName();
502                     if (current_prefix == child_prefix)
503                     {
504                         found = true;
505                         std::string new_name;
506                         for (int j = 0; j < names.GetArgumentCount(); ++j)
507                         {
508                             if (j > 0)
509                                 new_name += '.';
510                             new_name += names.GetArgumentAtIndex (j);
511                         }
512                         return child->SetVariable (new_name.c_str(), value, op, override, debugger_instance_name,
513                                                    index_value);
514                     }
515                 }
516                 if (!found)
517                 {
518                     err.SetErrorStringWithFormat ("unable to find variable '%s', cannot assign value",
519                                                   full_dot_name);
520                     return err;
521                 }
522             }
523         }
524     }
525     else
526     {
527         err.SetErrorStringWithFormat ("'%s' is not a valid level name; was expecting '%s', cannot assign value",
528                                       prefix.GetCString(), m_settings.level_name.GetCString());
529     }
530 
531     return err;
532 }
533 
534 StringList
535 UserSettingsController::GetVariable
536 (
537     const char *full_dot_name,
538     SettableVariableType &var_type,
539     const char *debugger_instance_name,
540     Error &err
541 )
542 {
543     StringList value;
544     if (!full_dot_name)
545     {
546         err.SetErrorString ("invalid variable name");
547         return value;
548     }
549 
550     Args names = UserSettingsController::BreakNameIntoPieces (full_dot_name);
551     int num_pieces = names.GetArgumentCount();
552 
553     ConstString const_var_name;
554 
555     ConstString prefix (names.GetArgumentAtIndex (0));
556     const_var_name.SetCString (names.GetArgumentAtIndex (num_pieces - 1));
557 
558     const SettingEntry *global_entry = GetGlobalEntry (const_var_name);
559     const SettingEntry *instance_entry = GetInstanceEntry (const_var_name);
560 
561     if ((prefix != m_settings.level_name)
562         && (m_settings.level_name.GetLength () > 0))
563     {
564         err.SetErrorString ("invalid variable name");
565         return value;
566     }
567 
568     // prefix name matched; remove it from names.
569     if (m_settings.level_name.GetLength() > 0)
570         names.Shift();
571 
572     // Should we pass this off to a child?  If there is more than one name piece left, and the next name piece
573     // matches a child prefix, then yes.
574 
575     UserSettingsControllerSP child;
576     if (names.GetArgumentCount() > 1)
577     {
578         ConstString child_prefix (names.GetArgumentAtIndex (0));
579         bool found = false;
580         for (int i = 0; i < m_children.size() && !found; ++i)
581         {
582             if (child_prefix == m_children[i]->GetLevelName())
583             {
584                 found = true;
585                 child = m_children[i];
586                 std::string new_name;
587                 for (int j = 0; j < names.GetArgumentCount(); ++j)
588                 {
589                     if (j > 0)
590                         new_name += '.';
591                     new_name += names.GetArgumentAtIndex (j);
592                 }
593                 return child->GetVariable (new_name.c_str(), var_type, debugger_instance_name, err);
594             }
595         }
596 
597         if (!found)
598         {
599             // Cannot be handled by a child, because name did not match any child prefixes.
600             // Cannot be a class-wide variable because there are too many name pieces.
601 
602             if (instance_entry != NULL)
603             {
604                 var_type = instance_entry->var_type;
605                 ConstString instance_name (names.GetArgumentAtIndex (0));
606                 InstanceSettings *current_settings = FindSettingsForInstance (instance_name);
607 
608                 if (current_settings != NULL)
609                 {
610                     current_settings->GetInstanceSettingsValue (*instance_entry, const_var_name, value, &err);
611                 }
612                 else
613                 {
614                     // Look for instance name setting in pending settings.
615 
616                     std::string inst_name_str = instance_name.GetCString();
617                     std::map<std::string, InstanceSettingsSP>::iterator pos;
618 
619                     pos = m_pending_settings.find (inst_name_str);
620                     if (pos != m_pending_settings.end())
621                     {
622                         InstanceSettingsSP settings_sp = pos->second;
623                         settings_sp->GetInstanceSettingsValue (*instance_entry, const_var_name,  value, &err);
624                     }
625                     else
626                     {
627                         if (m_settings.level_name.GetLength() > 0)
628                         {
629                             // No valid instance name; assume they want the default settings.
630                             m_default_settings->GetInstanceSettingsValue (*instance_entry, const_var_name, value, &err);
631                         }
632                         else
633                         {
634                             // We're at the Debugger level;  use the debugger's instance settings.
635                             StreamString tmp_name;
636                             if (debugger_instance_name[0] != '[')
637                                 tmp_name.Printf ("[%s]", debugger_instance_name);
638                             else
639                                 tmp_name.Printf ("%s", debugger_instance_name);
640                             ConstString dbg_name (debugger_instance_name);
641                             InstanceSettings *dbg_settings = FindSettingsForInstance (dbg_name);
642                             if (dbg_settings)
643                                 dbg_settings->GetInstanceSettingsValue (*instance_entry, const_var_name, value, &err);
644                         }
645                     }
646                 }
647             }
648             else
649                 err.SetErrorString ("invalid variable name");
650         }
651     }
652     else
653     {
654         // Only one name left.  It must belong to the current level, or be an error.
655         if ((global_entry == NULL)
656             && (instance_entry == NULL))
657         {
658             err.SetErrorString ("invalid variable name");
659         }
660         else if (global_entry)
661         {
662             var_type = global_entry->var_type;
663             GetGlobalVariable (const_var_name, value, err);
664         }
665         else if (instance_entry)
666         {
667             var_type = instance_entry->var_type;
668             if (m_settings.level_name.GetLength() > 0)
669                 m_default_settings->GetInstanceSettingsValue  (*instance_entry, const_var_name, value, &err);
670             else
671             {
672                 // We're at the Debugger level;  use the debugger's instance settings.
673                 StreamString tmp_name;
674                 if (debugger_instance_name[0] != '[')
675                     tmp_name.Printf ("[%s]", debugger_instance_name);
676                 else
677                     tmp_name.Printf ("%s", debugger_instance_name);
678                 ConstString dbg_name (tmp_name.GetData());
679                 InstanceSettings *dbg_settings = FindSettingsForInstance (dbg_name);
680                 if (dbg_settings)
681                     dbg_settings->GetInstanceSettingsValue (*instance_entry, const_var_name, value, &err);
682             }
683         }
684     }
685 
686     return value;
687 }
688 
689 void
690 UserSettingsController::RemovePendingSettings (const ConstString &instance_name)
691 {
692     StreamString tmp_name;
693 
694     // Add surrounding brackets to instance name if not already present.
695 
696     if (instance_name.GetCString()[0] != '[')
697         tmp_name.Printf ("[%s]", instance_name.GetCString());
698     else
699         tmp_name.Printf ("%s", instance_name.GetCString());
700 
701     std::string instance_name_str (tmp_name.GetData());
702     std::map<std::string, InstanceSettingsSP>::iterator pos;
703     Mutex::Locker locker (m_pending_settings_mutex);
704 
705     m_pending_settings.erase (instance_name_str);
706 }
707 
708 const InstanceSettingsSP &
709 UserSettingsController::FindPendingSettings (const ConstString &instance_name)
710 {
711     std::map<std::string, InstanceSettingsSP>::iterator pos;
712     StreamString tmp_name;
713 
714     // Add surrounding brackets to instance name if not already present.
715 
716     if (instance_name.GetCString()[0] != '[')
717         tmp_name.Printf ("[%s]", instance_name.GetCString());
718     else
719         tmp_name.Printf ("%s", instance_name.GetCString());
720 
721     std::string instance_name_str (tmp_name.GetData());  // Need std::string for std::map look-up
722 
723     {   // Scope for mutex.
724         Mutex::Locker locker (m_pending_settings_mutex);
725 
726         pos = m_pending_settings.find (instance_name_str);
727         if (pos != m_pending_settings.end())
728             return pos->second;
729     }
730 
731     return m_default_settings;
732 }
733 
734 void
735 UserSettingsController::CreateDefaultInstanceSettings ()
736 {
737     Error err;
738     const ConstString &default_instance_name = InstanceSettings::GetDefaultName();
739     for (int i = 0; i < m_settings.instance_settings.size(); ++i)
740     {
741         SettingEntry &entry = m_settings.instance_settings[i];
742         ConstString var_name (entry.var_name);
743         const char *default_value = entry.default_value;
744 
745         // If there is no default value, then use the first enumeration value
746         // as the default value
747         if (default_value == NULL && entry.var_type == eSetVarTypeEnum)
748             default_value = entry.enum_values[0].string_value;
749 
750         if (default_value != NULL)
751             m_default_settings->UpdateInstanceSettingsVariable (var_name,
752                                                                 NULL,
753                                                                 default_value,
754                                                                 default_instance_name,
755                                                                 entry,
756                                                                 eVarSetOperationAssign,
757                                                                 err,
758                                                                 true);
759     }
760 }
761 
762 void
763 UserSettingsController::CopyDefaultSettings (const InstanceSettingsSP &actual_settings,
764                                              const ConstString &instance_name,
765                                              bool pending)
766 {
767     Error err;
768     for (int i = 0; i < m_settings.instance_settings.size(); ++i)
769     {
770         SettingEntry &entry = m_settings.instance_settings[i];
771         ConstString var_name (entry.var_name);
772         StringList value;
773         m_default_settings->GetInstanceSettingsValue (entry, var_name, value, NULL);
774 
775         std::string value_str;
776         if (value.GetSize() == 1)
777             value_str.append (value.GetStringAtIndex (0));
778         else if (value.GetSize() > 1)
779         {
780             for (int j = 0; j < value.GetSize(); ++j)
781             {
782                 if (j > 0)
783                     value_str.append (" ");
784               value_str.append (value.GetStringAtIndex (j));
785             }
786         }
787 
788         actual_settings->UpdateInstanceSettingsVariable (var_name, NULL, value_str.c_str(), instance_name, entry,
789                                                          eVarSetOperationAssign, err, pending);
790 
791     }
792 }
793 
794 InstanceSettingsSP
795 UserSettingsController::PendingSettingsForInstance (const ConstString &instance_name)
796 {
797     std::string name_str (instance_name.GetCString());
798     std::map<std::string, InstanceSettingsSP>::iterator pos;
799     Mutex::Locker locker (m_pending_settings_mutex);
800 
801     pos = m_pending_settings.find (name_str);
802     if (pos != m_pending_settings.end())
803     {
804         InstanceSettingsSP settings_sp = pos->second;
805         return settings_sp;
806     }
807     else
808     {
809         InstanceSettingsSP new_settings_sp = CreateInstanceSettings (instance_name.GetCString());
810         CopyDefaultSettings (new_settings_sp, instance_name, true);
811         m_pending_settings[name_str] = new_settings_sp;
812         return new_settings_sp;
813     }
814 
815     // Should never reach this line.
816 
817     InstanceSettingsSP dummy;
818 
819     return dummy;
820 }
821 
822 void
823 UserSettingsController::GetAllDefaultSettingValues (Stream &strm)
824 {
825     std::string parent_prefix;
826     BuildParentPrefix (parent_prefix);
827 
828     for (int i = 0; i < m_settings.instance_settings.size(); ++i)
829     {
830         SettingEntry &entry = m_settings.instance_settings[i];
831         ConstString var_name (entry.var_name);
832         StringList value;
833         m_default_settings->GetInstanceSettingsValue (entry, var_name, value, NULL);
834 
835         if (!parent_prefix.empty())
836             strm.Printf ("%s.", parent_prefix.c_str());
837 
838         DumpValue (var_name.GetCString(),
839                    entry.var_type,
840                    value,
841                    strm);
842     }
843 }
844 
845 void
846 UserSettingsController::GetAllPendingSettingValues (Stream &strm)
847 {
848     std::map<std::string, InstanceSettingsSP>::iterator pos;
849 
850     std::string parent_prefix;
851     BuildParentPrefix (parent_prefix);
852     const char *prefix = parent_prefix.c_str();
853 
854     for (pos = m_pending_settings.begin(); pos != m_pending_settings.end(); ++pos)
855     {
856         std::string tmp_name = pos->first;
857         InstanceSettingsSP settings_sp = pos->second;
858 
859         const ConstString instance_name (tmp_name.c_str());
860 
861         for (int i = 0; i < m_settings.instance_settings.size(); ++i)
862         {
863             SettingEntry &entry = m_settings.instance_settings[i];
864             ConstString var_name (entry.var_name);
865             StringList tmp_value;
866             settings_sp->GetInstanceSettingsValue (entry, var_name, tmp_value, NULL);
867 
868             StreamString value_str;
869 
870             if (tmp_value.GetSize() == 1)
871                 value_str.Printf ("%s", tmp_value.GetStringAtIndex (0));
872             else
873             {
874                 for (int j = 0; j < tmp_value.GetSize(); ++j)
875                     value_str.Printf  ("%s ", tmp_value.GetStringAtIndex (j));
876             }
877 
878             if (parent_prefix.length() > 0)
879             {
880                 strm.Printf ("%s.%s.%s (%s) = '%s' [pending]\n", prefix, instance_name.GetCString(),
881                                       var_name.GetCString(), UserSettingsController::GetTypeString (entry.var_type),
882                                       value_str.GetData());
883             }
884             else
885             {
886                 strm.Printf ("%s (%s) = '%s' [pending]\n", var_name.GetCString(),
887                                       UserSettingsController::GetTypeString (entry.var_type),
888                                       value_str.GetData());
889             }
890         }
891     }
892 }
893 
894 InstanceSettings *
895 UserSettingsController::FindSettingsForInstance (const ConstString &instance_name)
896 {
897     std::string instance_name_str (instance_name.GetCString());
898     Mutex::Locker locker (m_live_settings_mutex);
899     InstanceSettingsMap::iterator pos = m_live_settings.find (instance_name_str);
900     if (pos != m_live_settings.end ())
901         return pos->second;
902     return NULL;
903 }
904 
905 void
906 UserSettingsController::GetAllInstanceVariableValues (CommandInterpreter &interpreter,
907                                                       Stream &strm)
908 {
909     std::string parent_prefix;
910     BuildParentPrefix (parent_prefix);
911     StreamString description;
912 
913     Mutex::Locker locker (m_live_settings_mutex);
914     for (InstanceSettingsMap::iterator pos = m_live_settings.begin(); pos != m_live_settings.end(); ++pos)
915     {
916         std::string instance_name = pos->first;
917         InstanceSettings *settings = pos->second;
918 
919         for (int i = 0; i < m_settings.instance_settings.size(); ++i)
920         {
921             SettingEntry &entry = m_settings.instance_settings[i];
922             const ConstString var_name (entry.var_name);
923             StringList tmp_value;
924             settings->GetInstanceSettingsValue (entry, var_name, tmp_value, NULL);
925 
926             if (!parent_prefix.empty())
927                 strm.Printf ("%s.", parent_prefix.c_str());
928 
929             DumpValue(var_name.GetCString(), entry.var_type, tmp_value, strm);
930         }
931     }
932 }
933 
934 void
935 UserSettingsController::OverrideAllInstances (const ConstString &var_name,
936                                               const char *value,
937                                               VarSetOperationType op,
938                                               const char *index_value,
939                                               Error &err)
940 {
941     StreamString description;
942 
943     Mutex::Locker locker (m_live_settings_mutex);
944     for (InstanceSettingsMap::iterator pos = m_live_settings.begin(); pos != m_live_settings.end(); ++pos)
945     {
946         InstanceSettings *settings = pos->second;
947         StreamString tmp_name;
948         tmp_name.Printf ("[%s]", settings->GetInstanceName().GetCString());
949         const ConstString instance_name (tmp_name.GetData());
950         const SettingEntry *entry = GetInstanceEntry (var_name);
951         settings->UpdateInstanceSettingsVariable (var_name, index_value, value, instance_name, *entry, op, err, false);
952 
953     }
954 }
955 
956 void
957 UserSettingsController::RegisterInstanceSettings (InstanceSettings *instance_settings)
958 {
959     Mutex::Locker locker (m_live_settings_mutex);
960     StreamString tmp_name;
961     tmp_name.Printf ("[%s]", instance_settings->GetInstanceName().GetCString());
962     const ConstString instance_name (tmp_name.GetData());
963     std::string instance_name_str (instance_name.GetCString());
964     if (instance_name_str.compare (InstanceSettings::GetDefaultName().GetCString()) != 0)
965         m_live_settings[instance_name_str] = instance_settings;
966 }
967 
968 void
969 UserSettingsController::UnregisterInstanceSettings (InstanceSettings *instance)
970 {
971     Mutex::Locker locker (m_live_settings_mutex);
972     StreamString tmp_name;
973     tmp_name.Printf ("[%s]", instance->GetInstanceName().GetCString());
974     std::string instance_name (tmp_name.GetData());
975 
976     InstanceSettingsMap::iterator pos = m_live_settings.find (instance_name);
977     if (pos != m_live_settings.end())
978         m_live_settings.erase (pos);
979 }
980 
981 void
982 UserSettingsController::CreateSettingsVector (const SettingEntry *table,
983                                               bool global)
984 {
985     int i = 0;
986     while (table[i].var_name != NULL)
987     {
988         const SettingEntry &table_entry = table[i];
989         ConstString const_var_name (table_entry.var_name);
990         SettingEntry new_entry;
991 
992         new_entry = table_entry;
993         new_entry.var_name = const_var_name.GetCString();
994 
995         if (global)
996             m_settings.global_settings.push_back (new_entry);
997         else
998             m_settings.instance_settings.push_back (new_entry);
999 
1000         ++i;
1001     }
1002 }
1003 
1004 //----------------------------------------------------------------------
1005 // UserSettingsController static methods
1006 //----------------------------------------------------------------------
1007 
1008 int
1009 FindMaxNameLength (std::vector<SettingEntry> table)
1010 {
1011     int max_length = 1;
1012 
1013     for (int i = 0; i < table.size(); ++i)
1014     {
1015         int len = strlen (table[i].var_name);
1016         if (len > max_length)
1017             max_length = len;
1018     }
1019 
1020     return max_length;
1021 }
1022 
1023 const char *
1024 UserSettingsController::GetTypeString (SettableVariableType var_type)
1025 {
1026     switch (var_type)
1027     {
1028         case eSetVarTypeInt:
1029             return "int";
1030         case eSetVarTypeBoolean:
1031             return "boolean";
1032         case eSetVarTypeString:
1033             return "string";
1034         case eSetVarTypeArray:
1035             return "array";
1036         case eSetVarTypeDictionary:
1037             return "dictionary";
1038         case eSetVarTypeEnum:
1039             return "enum";
1040         case eSetVarTypeNone:
1041             return "no type";
1042     }
1043 
1044     return "";
1045 }
1046 
1047 void
1048 UserSettingsController::PrintEnumValues (const OptionEnumValueElement *enum_values, Stream &str)
1049 {
1050     int i = 0;
1051     while (enum_values[i].string_value != NULL)
1052     {
1053         str.Printf ("%s ", enum_values[i].string_value);
1054         ++i;
1055     }
1056 
1057 }
1058 
1059 void
1060 UserSettingsController::FindAllSettingsDescriptions (CommandInterpreter &interpreter,
1061                                                      const UserSettingsControllerSP& usc_sp,
1062                                                      const char *current_prefix,
1063                                                      Stream &strm,
1064                                                      Error &err)
1065 {
1066     // Write out current prefix line.
1067     StreamString prefix_line;
1068     StreamString description;
1069     uint32_t max_len = FindMaxNameLength (usc_sp->m_settings.global_settings);
1070     int num_entries = usc_sp->m_settings.global_settings.size();
1071 
1072     if (current_prefix && current_prefix[0])
1073         strm.Printf ("\n'%s' variables:\n\n", current_prefix);
1074     else
1075         strm.Printf ("\nTop level variables:\n\n");
1076 
1077     if (num_entries > 0)
1078     {
1079         // Write out all "global" variables.
1080         for (int i = 0; i < num_entries; ++i)
1081         {
1082             DumpSettingEntry (interpreter, strm, max_len, usc_sp->m_settings.global_settings[i]);
1083         }
1084     }
1085 
1086     num_entries = usc_sp->m_settings.instance_settings.size();
1087     max_len = FindMaxNameLength (usc_sp->m_settings.instance_settings);
1088 
1089     if (num_entries > 0)
1090     {
1091         // Write out all instance variables.
1092         for (int i = 0; i < num_entries; ++i)
1093         {
1094             DumpSettingEntry (interpreter, strm, max_len, usc_sp->m_settings.instance_settings[i]);
1095         }
1096     }
1097 
1098     // Now, recurse across all children.
1099     int num_children = usc_sp->GetNumChildren();
1100     for (int i = 0; i < num_children; ++i)
1101     {
1102         UserSettingsControllerSP child = usc_sp->GetChildAtIndex (i);
1103 
1104         if (child)
1105         {
1106             ConstString child_prefix = child->GetLevelName();
1107             if (current_prefix && current_prefix[0])
1108             {
1109                 StreamString new_prefix;
1110                 new_prefix.Printf ("%s.%s", current_prefix, child_prefix.GetCString());
1111                 UserSettingsController::FindAllSettingsDescriptions (interpreter,
1112                                                                      child,
1113                                                                      new_prefix.GetData(),
1114                                                                      strm,
1115                                                                      err);
1116             }
1117             else
1118             {
1119                 UserSettingsController::FindAllSettingsDescriptions (interpreter,
1120                                                                      child,
1121                                                                      child_prefix.GetCString(),
1122                                                                      strm,
1123                                                                      err);
1124             }
1125         }
1126     }
1127 }
1128 
1129 void
1130 UserSettingsController::FindSettingsDescriptions (CommandInterpreter &interpreter,
1131                                                   const UserSettingsControllerSP& usc_sp,
1132                                                   const char *current_prefix,
1133                                                   const char *search_name,
1134                                                   Stream &strm,
1135                                                   Error &err)
1136 {
1137     Args names = UserSettingsController::BreakNameIntoPieces (search_name);
1138     int num_pieces = names.GetArgumentCount ();
1139 
1140     if (num_pieces == 0)
1141         return;
1142 
1143     if (usc_sp->GetLevelName().GetLength() > 0)
1144     {
1145         ConstString prefix (names.GetArgumentAtIndex (0));
1146         if (prefix != usc_sp->GetLevelName())
1147         {
1148             std::string parent_prefix;
1149             usc_sp->BuildParentPrefix (parent_prefix);
1150             err.SetErrorStringWithFormat ("cannot find match for '%s.%s'", parent_prefix.c_str(),
1151                                           prefix.GetCString());
1152             return;
1153         }
1154         else
1155         {
1156             names.Shift();
1157             --num_pieces;
1158         }
1159     }
1160 
1161     // If there's nothing left then dump all global and instance descriptions for this root.
1162     if (num_pieces == 0)
1163     {
1164         StreamString prefix_line;
1165         StreamString description;
1166         uint32_t max_len;
1167         int num_entries = usc_sp->m_settings.global_settings.size();
1168 
1169         max_len = FindMaxNameLength (usc_sp->m_settings.global_settings);
1170 
1171         strm.Printf ("\n'%s' variables:\n\n", search_name);
1172 
1173         if (num_entries > 0)
1174         {
1175             // Write out all "global" variables.
1176             for (int i = 0; i < num_entries; ++i)
1177             {
1178                 DumpSettingEntry (interpreter, strm, max_len, usc_sp->m_settings.global_settings[i]);
1179             }
1180         }
1181 
1182         num_entries = usc_sp->m_settings.instance_settings.size();
1183         max_len = FindMaxNameLength (usc_sp->m_settings.instance_settings);
1184 
1185         if (num_entries > 0)
1186         {
1187             // Write out all instance variables.
1188             for (int i = 0; i < num_entries; ++i)
1189             {
1190                 DumpSettingEntry (interpreter, strm, max_len, usc_sp->m_settings.instance_settings[i]);
1191             }
1192         }
1193     }
1194     else if (num_pieces == 1)
1195     {
1196         ConstString var_name (names.GetArgumentAtIndex (0));
1197         bool is_global = false;
1198 
1199         const SettingEntry *setting_entry = usc_sp->GetGlobalEntry (var_name);
1200 
1201         if (setting_entry == NULL)
1202             setting_entry = usc_sp->GetInstanceEntry (var_name);
1203         else
1204             is_global = true;
1205 
1206         // Check to see if it is a global or instance variable name.
1207         if (setting_entry != NULL)
1208         {
1209             DumpSettingEntry (interpreter, strm, var_name.GetLength(), *setting_entry);
1210         }
1211         else
1212         {
1213             // It must be a child name.
1214             int num_children = usc_sp->GetNumChildren();
1215             bool found = false;
1216             for (int i = 0; i < num_children && !found; ++i)
1217             {
1218                 UserSettingsControllerSP child = usc_sp->GetChildAtIndex (i);
1219                 if (child)
1220                 {
1221                     ConstString child_prefix = child->GetLevelName();
1222                     if (child_prefix == var_name)
1223                     {
1224                         found = true;
1225                         UserSettingsController::FindSettingsDescriptions (interpreter,
1226                                                                           child,
1227                                                                           current_prefix,
1228                                                                           var_name.GetCString(),
1229                                                                           strm,
1230                                                                           err);
1231                     }
1232                 }
1233             }
1234             if (!found)
1235             {
1236                 std::string parent_prefix;
1237                 usc_sp->BuildParentPrefix (parent_prefix);
1238                 err.SetErrorStringWithFormat ("cannot find match for '%s.%s'", parent_prefix.c_str(), search_name);
1239                 return;
1240             }
1241         }
1242     }
1243     else
1244     {
1245         // It must be a child name; find the child and call this function recursively on child.
1246         ConstString child_name (names.GetArgumentAtIndex (0));
1247 
1248         StreamString rest_of_search_name;
1249         for (int i = 0; i < num_pieces; ++i)
1250         {
1251             rest_of_search_name.Printf ("%s", names.GetArgumentAtIndex (i));
1252             if ((i + 1) < num_pieces)
1253                 rest_of_search_name.Printf (".");
1254         }
1255 
1256         int num_children = usc_sp->GetNumChildren();
1257         bool found = false;
1258         for (int i = 0; i < num_children && !found; ++i)
1259         {
1260             UserSettingsControllerSP child = usc_sp->GetChildAtIndex (i);
1261             if (child)
1262             {
1263                 ConstString child_prefix = child->GetLevelName();
1264                 if (child_prefix == child_name)
1265                 {
1266                     found = true;
1267                     UserSettingsController::FindSettingsDescriptions (interpreter, child, current_prefix,
1268                                                                       rest_of_search_name.GetData(), strm,
1269                                                                       err);
1270                 }
1271             }
1272         }
1273         if (!found)
1274         {
1275             std::string parent_prefix;
1276             usc_sp->BuildParentPrefix (parent_prefix);
1277             err.SetErrorStringWithFormat ("cannot find match for '%s.%s'", parent_prefix.c_str(), search_name);
1278             return;
1279         }
1280     }
1281 }
1282 
1283 void
1284 UserSettingsController::SearchAllSettingsDescriptions (CommandInterpreter &interpreter,
1285                                                        const UserSettingsControllerSP& usc_sp,
1286                                                        const char *current_prefix,
1287                                                        const char *search_word,
1288                                                        Stream &strm)
1289 {
1290     if ((search_word == NULL) || (strlen (search_word) == 0))
1291         return;
1292 
1293     int num_entries = usc_sp->m_settings.global_settings.size();
1294 
1295     if (num_entries > 0)
1296     {
1297         for (int i = 0; i < num_entries; ++i)
1298         {
1299             const SettingEntry &entry = usc_sp->m_settings.global_settings[i];
1300             if (strcasestr (entry.description, search_word) != NULL)
1301             {
1302                 StreamString var_name;
1303                 if (current_prefix && current_prefix[0])
1304                     var_name.Printf ("%s.%s", current_prefix, entry.var_name);
1305                 else
1306                     var_name.Printf ("%s", entry.var_name);
1307                 interpreter.OutputFormattedHelpText (strm, var_name.GetData(), "--", entry.description,
1308                                                      var_name.GetSize());
1309             }
1310         }
1311     }
1312 
1313     num_entries = usc_sp->m_settings.instance_settings.size();
1314     if (num_entries > 0)
1315     {
1316         for (int i = 0; i < num_entries; ++i)
1317         {
1318             SettingEntry &entry = usc_sp->m_settings.instance_settings[i];
1319             if (strcasestr (entry.description, search_word) != NULL)
1320             {
1321                 StreamString var_name;
1322                 if (current_prefix && current_prefix[0])
1323                     var_name.Printf ("%s.%s", current_prefix, entry.var_name);
1324                 else
1325                     var_name.Printf ("%s", entry.var_name);
1326                 interpreter.OutputFormattedHelpText (strm,
1327                                                      var_name.GetData(),
1328                                                      "--",
1329                                                      entry.description,
1330                                                      var_name.GetSize());
1331             }
1332         }
1333     }
1334 
1335     int num_children = usc_sp->GetNumChildren ();
1336     for (int i = 0; i < num_children; ++i)
1337     {
1338         UserSettingsControllerSP child = usc_sp->GetChildAtIndex (i);
1339 
1340         if (child)
1341         {
1342             ConstString child_prefix = child->GetLevelName();
1343             if (current_prefix && current_prefix[0])
1344             {
1345                 StreamString new_prefix;
1346                 new_prefix.Printf ("%s.%s", current_prefix, child_prefix.GetCString());
1347                 UserSettingsController::SearchAllSettingsDescriptions (interpreter,
1348                                                                        child,
1349                                                                        new_prefix.GetData(),
1350                                                                        search_word,
1351                                                                        strm);
1352             }
1353             else
1354             {
1355                 UserSettingsController::SearchAllSettingsDescriptions (interpreter,
1356                                                                        child,
1357                                                                        child_prefix.GetCString(),
1358                                                                        search_word,
1359                                                                        strm);
1360             }
1361         }
1362     }
1363 }
1364 
1365 bool
1366 UserSettingsController::DumpValue (CommandInterpreter &interpreter,
1367                                    const UserSettingsControllerSP& usc_sp,
1368                                    const char *variable_dot_name,
1369                                    Stream &strm)
1370 {
1371     SettableVariableType var_type;
1372     Error err;
1373     StringList value = usc_sp->GetVariable (variable_dot_name,
1374                                             var_type,
1375                                             interpreter.GetDebugger().GetInstanceName().GetCString(),
1376                                             err);
1377 
1378     if (err.Success())
1379         return DumpValue (variable_dot_name, var_type, value, strm);
1380     return false;
1381 }
1382 
1383 
1384 bool
1385 UserSettingsController::DumpValue (const char *variable_dot_name,
1386                                    SettableVariableType var_type,
1387                                    const StringList &value,
1388                                    Stream &strm)
1389 {
1390     const char *type_name = UserSettingsController::GetTypeString (var_type);
1391 
1392     strm.Printf ("%s (%s) = ", variable_dot_name, type_name);
1393     if (value.GetSize() == 0)
1394     {
1395         strm.EOL();
1396     }
1397     else
1398     {
1399         switch (var_type)
1400         {
1401             case eSetVarTypeNone:
1402             case eSetVarTypeEnum:
1403             case eSetVarTypeInt:
1404             case eSetVarTypeBoolean:
1405                 strm.Printf ("%s\n", value.GetStringAtIndex (0));
1406                 break;
1407 
1408             case eSetVarTypeString:
1409                 strm.Printf ("\"%s\"\n", value.GetStringAtIndex (0));
1410                 break;
1411 
1412             case eSetVarTypeArray:
1413                 {
1414                     strm.EOL();
1415                     for (unsigned i = 0, e = value.GetSize(); i != e; ++i)
1416                         strm.Printf ("  [%u]: \"%s\"\n", i, value.GetStringAtIndex (i));
1417                 }
1418                 break;
1419 
1420             case eSetVarTypeDictionary:
1421                 {
1422                     strm.EOL();
1423                     for (unsigned i = 0, e = value.GetSize(); i != e; ++i)
1424                         strm.Printf ("  %s\n", value.GetStringAtIndex (i));
1425                 }
1426                 break;
1427 
1428             default:
1429                 return false;
1430         }
1431     }
1432     return true;
1433 }
1434 
1435 void
1436 UserSettingsController::GetAllVariableValues (CommandInterpreter &interpreter,
1437                                               const UserSettingsControllerSP& usc_sp,
1438                                               const char *current_prefix,
1439                                               Stream &strm,
1440                                               Error &err)
1441 {
1442     StreamString description;
1443     int num_entries = usc_sp->m_settings.global_settings.size();
1444 
1445     for (int i = 0; i < num_entries; ++i)
1446     {
1447         StreamString full_var_name;
1448         const SettingEntry &entry = usc_sp->m_settings.global_settings[i];
1449 
1450         if (current_prefix && current_prefix[0])
1451             full_var_name.Printf ("%s.%s", current_prefix, entry.var_name);
1452         else
1453             full_var_name.Printf ("%s", entry.var_name);
1454 
1455         DumpValue (interpreter, usc_sp, full_var_name.GetData(),  strm);
1456     }
1457 
1458     usc_sp->GetAllInstanceVariableValues (interpreter, strm);
1459     usc_sp->GetAllPendingSettingValues (strm);
1460     if (usc_sp->GetLevelName().GetLength() > 0)               // Don't bother with default values for Debugger level.
1461          usc_sp->GetAllDefaultSettingValues (strm);
1462 
1463 
1464     // Now, recurse across all children.
1465     int num_children = usc_sp->GetNumChildren();
1466     for (int i = 0; i < num_children; ++i)
1467     {
1468         UserSettingsControllerSP child = usc_sp->GetChildAtIndex (i);
1469 
1470         if (child)
1471         {
1472             ConstString child_prefix = child->GetLevelName();
1473             if (current_prefix && current_prefix[0])
1474             {
1475                 StreamString new_prefix;
1476                 new_prefix.Printf ("%s.%s", current_prefix, child_prefix.GetCString());
1477                 UserSettingsController::GetAllVariableValues (interpreter,
1478                                                               child,
1479                                                               new_prefix.GetData(),
1480                                                               strm,
1481                                                               err);
1482             }
1483             else
1484             {
1485                 UserSettingsController::GetAllVariableValues (interpreter,
1486                                                               child,
1487                                                               child_prefix.GetCString(),
1488                                                               strm,
1489                                                               err);
1490             }
1491         }
1492     }
1493 
1494 }
1495 
1496 Args
1497 UserSettingsController::BreakNameIntoPieces (const char *full_dot_name)
1498 {
1499     Args return_value;
1500     std::string name_string (full_dot_name);
1501     bool done = false;
1502 
1503     std::string piece;
1504     std::string remainder (full_dot_name);
1505 
1506     while (!done)
1507     {
1508         size_t idx = remainder.find_first_of ('.');
1509         piece = remainder.substr (0, idx);
1510         return_value.AppendArgument (piece.c_str());
1511         if (idx != std::string::npos)
1512             remainder = remainder.substr (idx+1);
1513         else
1514             done = true;
1515     }
1516 
1517     return return_value;
1518 }
1519 
1520 bool
1521 UserSettingsController::IsLiveInstance (const std::string &instance_name)
1522 {
1523     Mutex::Locker locker (m_live_settings_mutex);
1524     InstanceSettingsMap::iterator pos = m_live_settings.find (instance_name);
1525     if (pos != m_live_settings.end())
1526         return true;
1527 
1528     return false;
1529 }
1530 
1531 int
1532 UserSettingsController::CompleteSettingsValue (const UserSettingsControllerSP& usc_sp,
1533                                                const char *full_dot_name,
1534                                                const char *partial_value,
1535                                                bool &word_complete,
1536                                                StringList &matches)
1537 {
1538     Args names = UserSettingsController::BreakNameIntoPieces (full_dot_name);
1539     int num_pieces = names.GetArgumentCount();
1540     word_complete = true;
1541 
1542     ConstString root_level = usc_sp->GetLevelName();
1543     int num_extra_levels = num_pieces - 2;
1544     if ((num_extra_levels > 0)
1545         && root_level.GetLength() > 0)
1546     {
1547         ConstString current_level (names.GetArgumentAtIndex (0));
1548         if (current_level == root_level)
1549         {
1550             names.Shift();
1551             --num_extra_levels;
1552         }
1553         else
1554             return 0;
1555     }
1556 
1557     for (int i = 0; i < num_extra_levels; ++i)
1558     {
1559         ConstString child_level (names.GetArgumentAtIndex (0));
1560         bool found = false;
1561         int num_children = usc_sp->GetNumChildren();
1562         UserSettingsControllerSP child_usc_sp = usc_sp;
1563         for (int j = 0; j < num_children && !found; ++j)
1564         {
1565             if (child_usc_sp->GetChildAtIndex (j)->GetLevelName() == child_level)
1566             {
1567                 found = true;
1568                 child_usc_sp = child_usc_sp->GetChildAtIndex (j);
1569                 names.Shift();
1570             }
1571         }
1572         if (!found)
1573             return 0;
1574     }
1575 
1576     if (names.GetArgumentCount() != 2)
1577         return 0;
1578 
1579     std::string next_name (names.GetArgumentAtIndex (0));
1580     int len = next_name.length();
1581     names.Shift();
1582 
1583     if ((next_name[0] == '[') && (next_name[len-1] == ']'))
1584     {
1585         // 'next_name' is instance name.  Instance names are irrelevent here.
1586     }
1587     else
1588     {
1589         // 'next_name' is child name.
1590         bool found = false;
1591         int num_children = usc_sp->GetNumChildren();
1592         ConstString child_level (next_name.c_str());
1593         UserSettingsControllerSP child_usc_sp = usc_sp;
1594         for (int j = 0; j < num_children && !found; ++j)
1595         {
1596             if (child_usc_sp->GetChildAtIndex (j)->GetLevelName() == child_level)
1597             {
1598                 found = true;
1599                 child_usc_sp = child_usc_sp->GetChildAtIndex (j);
1600             }
1601         }
1602         if (!found)
1603             return 0;
1604     }
1605 
1606     ConstString var_name (names.GetArgumentAtIndex(0));
1607     const SettingEntry *entry = usc_sp->GetGlobalEntry (var_name);
1608     if (entry == NULL)
1609         entry = usc_sp->GetInstanceEntry (var_name);
1610 
1611     if (entry == NULL)
1612         return 0;
1613 
1614     if (entry->var_type == eSetVarTypeBoolean)
1615         return UserSettingsController::BooleanMatches (partial_value, word_complete, matches);
1616     else if (entry->var_type == eSetVarTypeEnum)
1617         return UserSettingsController::EnumMatches (partial_value, entry->enum_values, word_complete, matches);
1618     else
1619         return 0;
1620 }
1621 
1622 int
1623 UserSettingsController::BooleanMatches (const char *partial_value,
1624                                         bool &word_complete,
1625                                         StringList &matches)
1626 {
1627     static const std::string true_string ("true");
1628     static const std::string false_string ("false");
1629 
1630     if (partial_value == NULL)
1631     {
1632         matches.AppendString ("true");
1633         matches.AppendString ("false");
1634     }
1635     else
1636     {
1637         int partial_len = strlen (partial_value);
1638 
1639         if ((partial_len <= true_string.length())
1640             && (true_string.find (partial_value) == 0))
1641             matches.AppendString ("true");
1642         else if ((partial_len <= false_string.length())
1643                  && (false_string.find (partial_value) == 0))
1644             matches.AppendString ("false");
1645     }
1646 
1647     word_complete = false;
1648     if (matches.GetSize() == 1)
1649         word_complete = true;
1650 
1651     return matches.GetSize();
1652 }
1653 
1654 int
1655 UserSettingsController::EnumMatches (const char *partial_value,
1656                                      OptionEnumValueElement *enum_values,
1657                                      bool &word_complete,
1658                                      StringList &matches)
1659 {
1660     int len = (partial_value != NULL) ? strlen (partial_value) : 0;
1661 
1662     int i = 0;
1663     while (enum_values[i].string_value != NULL)
1664     {
1665         if (len == 0)
1666             matches.AppendString (enum_values[i].string_value);
1667         else
1668         {
1669             std::string tmp_value (enum_values[i].string_value);
1670             if ((len <= tmp_value.length())
1671                 && tmp_value.find (partial_value) == 0)
1672               matches.AppendString (enum_values[i].string_value);
1673         }
1674         ++i;
1675     }
1676 
1677     word_complete = false;
1678     if (matches.GetSize() == 1)
1679       word_complete = true;
1680 
1681     return matches.GetSize();
1682 }
1683 
1684 int
1685 UserSettingsController::CompleteSettingsNames (const UserSettingsControllerSP& usc_sp,
1686                                                Args &partial_setting_name_pieces,
1687                                                bool &word_complete,
1688                                                StringList &matches)
1689 {
1690     int num_matches = 0;
1691     int num_name_pieces = partial_setting_name_pieces.GetArgumentCount();
1692 
1693     if (num_name_pieces > 1)
1694     {
1695         // There are at least two pieces, perhaps with multiple level names preceding them.
1696         // First traverse all the extra levels, until we have exactly two pieces left.
1697 
1698         int num_extra_levels = num_name_pieces - 2;
1699 
1700         // Deal with current level first.
1701 
1702         ConstString root_level = usc_sp->GetLevelName();
1703         if ((num_extra_levels > 0)
1704             && (root_level.GetLength() > 0))
1705         {
1706             ConstString current_level (partial_setting_name_pieces.GetArgumentAtIndex (0));
1707             if (current_level == root_level)
1708             {
1709                 partial_setting_name_pieces.Shift();
1710                 --num_extra_levels;
1711             }
1712             else
1713                 return 0; // The current level did not match the name pieces; something is wrong, so return immediately
1714 
1715         }
1716 
1717         for (int i = 0; i < num_extra_levels; ++i)
1718         {
1719             ConstString child_level (partial_setting_name_pieces.GetArgumentAtIndex (0));
1720             bool found = false;
1721             int num_children = usc_sp->GetNumChildren();
1722             UserSettingsControllerSP child_usc_sp = usc_sp;
1723 
1724             for (int j = 0; j < num_children && !found; ++j)
1725             {
1726                 if (child_usc_sp->GetChildAtIndex (j)->GetLevelName() == child_level)
1727                 {
1728                     found = true;
1729                     child_usc_sp = child_usc_sp->GetChildAtIndex (j);
1730                     partial_setting_name_pieces.Shift();
1731                 }
1732             }
1733             if (! found)
1734             {
1735                 return 0; // Unable to find a matching child level name; something is wrong, so return immediately.
1736             }
1737         }
1738 
1739         // Now there should be exactly two name pieces left.  If not there is an error, so return immediately
1740 
1741         if (partial_setting_name_pieces.GetArgumentCount() != 2)
1742             return 0;
1743 
1744         std::string next_name (partial_setting_name_pieces.GetArgumentAtIndex (0));
1745         int len = next_name.length();
1746         partial_setting_name_pieces.Shift();
1747 
1748         if ((next_name[0] == '[') && (next_name[len-1] == ']'))
1749         {
1750             // 'next_name' is an instance name.  The last name piece must be a non-empty partial match against an
1751             // instance_name, assuming 'next_name' is valid.
1752 
1753             if (usc_sp->IsLiveInstance (next_name))
1754             {
1755                 std::string complete_prefix;
1756                 usc_sp->BuildParentPrefix (complete_prefix);
1757 
1758                 num_matches = usc_sp->InstanceVariableMatches(partial_setting_name_pieces.GetArgumentAtIndex(0),
1759                                                                      complete_prefix,
1760                                                                      next_name.c_str(),
1761                                                                      matches);
1762                 word_complete = true;
1763                 if (num_matches > 1)
1764                     word_complete = false;
1765 
1766                 return num_matches;
1767             }
1768             else
1769                 return 0;   // Invalid instance_name
1770         }
1771         else
1772         {
1773             // 'next_name' must be a child name.  Find the correct child and pass the remaining piece to be resolved.
1774             bool found = false;
1775             int num_children = usc_sp->GetNumChildren();
1776             ConstString child_level (next_name.c_str());
1777             for (int i = 0; i < num_children; ++i)
1778             {
1779                 if (usc_sp->GetChildAtIndex (i)->GetLevelName() == child_level)
1780                 {
1781                     found = true;
1782                     return UserSettingsController::CompleteSettingsNames (usc_sp->GetChildAtIndex (i),
1783                                                                           partial_setting_name_pieces,
1784                                                                           word_complete, matches);
1785                 }
1786             }
1787             if (!found)
1788                 return 0;
1789         }
1790     }
1791     else if (num_name_pieces == 1)
1792     {
1793         std::string complete_prefix;
1794         usc_sp->BuildParentPrefix (complete_prefix);
1795 
1796         word_complete = true;
1797         std::string name (partial_setting_name_pieces.GetArgumentAtIndex (0));
1798 
1799         if (name[0] == '[')
1800         {
1801             // It's a partial instance name.
1802 
1803             num_matches = usc_sp->LiveInstanceMatches (name.c_str(), complete_prefix, word_complete, matches);
1804         }
1805         else
1806         {
1807             // It could be anything *except* an instance name...
1808 
1809             num_matches = usc_sp->GlobalVariableMatches (name.c_str(), complete_prefix, matches);
1810             num_matches += usc_sp->InstanceVariableMatches (name.c_str(), complete_prefix, NULL, matches);
1811             num_matches += usc_sp->ChildMatches (name.c_str(), complete_prefix, word_complete, matches);
1812         }
1813 
1814         if (num_matches > 1)
1815             word_complete = false;
1816 
1817         return num_matches;
1818     }
1819     else
1820     {
1821         // We have a user settings controller with a blank partial string.  Return everything possible at this level.
1822 
1823         std::string complete_prefix;
1824         usc_sp->BuildParentPrefix (complete_prefix);
1825         num_matches = usc_sp->GlobalVariableMatches (NULL, complete_prefix, matches);
1826         num_matches += usc_sp->InstanceVariableMatches (NULL, complete_prefix, NULL, matches);
1827         num_matches += usc_sp->LiveInstanceMatches (NULL, complete_prefix, word_complete, matches);
1828         num_matches += usc_sp->ChildMatches (NULL, complete_prefix, word_complete, matches);
1829         word_complete = false;
1830         return num_matches;
1831     }
1832 
1833     return num_matches;
1834 }
1835 
1836 int
1837 UserSettingsController::GlobalVariableMatches (const char *partial_name,
1838                                                const std::string &complete_prefix,
1839                                                StringList &matches)
1840 {
1841     int partial_len = (partial_name != NULL) ? strlen (partial_name) : 0;
1842     int num_matches = 0;
1843 
1844     for (size_t i = 0; i < m_settings.global_settings.size(); ++i)
1845     {
1846         const SettingEntry &entry = m_settings.global_settings[i];
1847         std::string var_name (entry.var_name);
1848         if ((partial_len == 0)
1849             || ((partial_len <= var_name.length())
1850                 && (var_name.find (partial_name) == 0)))
1851         {
1852             StreamString match_name;
1853             if (complete_prefix.length() > 0)
1854             {
1855                 match_name.Printf ("%s.%s", complete_prefix.c_str(), var_name.c_str());
1856                 matches.AppendString (match_name.GetData());
1857             }
1858             else
1859                 matches.AppendString (var_name.c_str());
1860             ++num_matches;
1861         }
1862     }
1863     return num_matches;
1864 }
1865 
1866 int
1867 UserSettingsController::InstanceVariableMatches (const char *partial_name,
1868                                                  const std::string &complete_prefix,
1869                                                  const char *instance_name,
1870                                                  StringList &matches)
1871 {
1872     int partial_len = (partial_name != NULL) ? strlen (partial_name) : 0;
1873     int num_matches = 0;
1874 
1875     for (size_t i = 0; i < m_settings.instance_settings.size(); ++i)
1876     {
1877         SettingEntry &entry = m_settings.instance_settings[i];
1878         std::string var_name (entry.var_name);
1879         if ((partial_len == 0)
1880             || ((partial_len <= var_name.length())
1881                 && (var_name.find (partial_name) == 0)))
1882         {
1883             StreamString match_name;
1884             if (complete_prefix.length() > 0)
1885             {
1886                 if (instance_name != NULL)
1887                     match_name.Printf ("%s.%s.%s", complete_prefix.c_str(), instance_name, var_name.c_str());
1888                 else
1889                     match_name.Printf ("%s.%s", complete_prefix.c_str(), var_name.c_str());
1890 
1891                 matches.AppendString (match_name.GetData());
1892             }
1893             else
1894             {
1895                 if (instance_name != NULL)
1896                 {
1897                     match_name.Printf ("%s.%s", instance_name, var_name.c_str());
1898                     matches.AppendString (match_name.GetData());
1899                 }
1900                 else
1901                     matches.AppendString (var_name.c_str());
1902             }
1903             ++num_matches;
1904         }
1905     }
1906     return num_matches;
1907 }
1908 
1909 int
1910 UserSettingsController::LiveInstanceMatches (const char *partial_name,
1911                                              const std::string &complete_prefix,
1912                                              bool &word_complete,
1913                                              StringList &matches)
1914 {
1915     int partial_len = (partial_name != NULL) ? strlen (partial_name) : 0;
1916     int num_matches = 0;
1917 
1918     InstanceSettingsMap::iterator pos;
1919     Mutex::Locker locker (m_live_settings_mutex);
1920     for (pos = m_live_settings.begin(); pos != m_live_settings.end(); ++pos)
1921     {
1922         std::string instance_name = pos->first;
1923         if ((partial_len == 0)
1924             || ((partial_len <= instance_name.length())
1925                 && (instance_name.find (partial_name) == 0)))
1926         {
1927             StreamString match_name;
1928             if (complete_prefix.length() > 0)
1929                 match_name.Printf ("%s.%s.", complete_prefix.c_str(), instance_name.c_str());
1930             else
1931                 match_name.Printf ("%s.", instance_name.c_str());
1932             matches.AppendString (match_name.GetData());
1933             ++num_matches;
1934         }
1935     }
1936 
1937     if (num_matches > 0)
1938         word_complete = false;
1939 
1940     return num_matches;
1941 }
1942 
1943 int
1944 UserSettingsController::ChildMatches (const char *partial_name,
1945                                       const std::string &complete_prefix,
1946                                       bool &word_complete,
1947                                       StringList &matches)
1948 {
1949     int partial_len = (partial_name != NULL) ? strlen (partial_name) : 0;
1950     int num_children = GetNumChildren();
1951     int num_matches = 0;
1952     for (int i = 0; i < num_children; ++i)
1953     {
1954         std::string child_name (GetChildAtIndex(i)->GetLevelName().GetCString());
1955         StreamString match_name;
1956         if ((partial_len == 0)
1957           || ((partial_len <= child_name.length())
1958               && (child_name.find (partial_name) == 0)))
1959         {
1960             if (complete_prefix.length() > 0)
1961                 match_name.Printf ("%s.%s.", complete_prefix.c_str(), child_name.c_str());
1962             else
1963                 match_name.Printf ("%s.", child_name.c_str());
1964             matches.AppendString (match_name.GetData());
1965             ++num_matches;
1966         }
1967     }
1968 
1969     if (num_matches > 0)
1970         word_complete = false;
1971 
1972     return num_matches;
1973 }
1974 
1975 void
1976 UserSettingsController::VerifyOperationForType (SettableVariableType var_type,
1977                                                 VarSetOperationType op,
1978                                                 const ConstString &var_name,
1979                                                 Error &err)
1980 {
1981     if (op == eVarSetOperationAssign)
1982         return;
1983 
1984 
1985     if (op == eVarSetOperationInvalid)
1986     {
1987         err.SetErrorString ("invalid 'settings' subcommand operation");
1988         return;
1989     }
1990 
1991     switch (op)
1992     {
1993         case eVarSetOperationInsertBefore:
1994         case eVarSetOperationInsertAfter:
1995             if (var_type != eSetVarTypeArray)
1996                 err.SetErrorString ("invalid operation: this operation can only be performed on array variables");
1997             break;
1998         case eVarSetOperationReplace:
1999         case eVarSetOperationRemove:
2000             if ((var_type != eSetVarTypeArray)
2001                 && (var_type != eSetVarTypeDictionary))
2002                 err.SetErrorString ("invalid operation: this operation can only be performed on array or dictionary variables");
2003             break;
2004         case eVarSetOperationAppend:
2005         case eVarSetOperationClear:
2006             if ((var_type != eSetVarTypeArray)
2007                 && (var_type != eSetVarTypeDictionary)
2008                 && (var_type != eSetVarTypeString))
2009                 err.SetErrorString ("invalid operation: this operation can only be performed on array, dictionary or string variables");
2010             break;
2011         default:
2012             break;
2013     }
2014 
2015     return;
2016 }
2017 
2018 void
2019 UserSettingsController::UpdateStringVariable (VarSetOperationType op,
2020                                               std::string &string_var,
2021                                               const char *new_value,
2022                                               Error &err)
2023 {
2024     if (op == eVarSetOperationAssign)
2025     {
2026         if (new_value && new_value[0])
2027             string_var.assign (new_value);
2028         else
2029             string_var.clear();
2030     }
2031     else if (op == eVarSetOperationAppend)
2032     {
2033         if (new_value && new_value[0])
2034             string_var.append (new_value);
2035     }
2036     else if (op == eVarSetOperationClear)
2037         string_var.clear();
2038     else
2039         err.SetErrorString ("unrecognized operation. Cannot update value");
2040 }
2041 
2042 Error
2043 UserSettingsController::UpdateStringOptionValue (const char *value,
2044                                                  VarSetOperationType op,
2045                                                  OptionValueString &option_value)
2046 {
2047     Error error;
2048     if (op == eVarSetOperationAssign)
2049     {
2050         option_value.SetCurrentValue (value);
2051     }
2052     else if (op == eVarSetOperationAppend)
2053     {
2054         option_value.AppendToCurrentValue (value);
2055     }
2056     else if (op == eVarSetOperationClear)
2057     {
2058         option_value.Clear();
2059     }
2060     else
2061     {
2062         error.SetErrorString ("unrecognized operation, cannot update value");
2063     }
2064     return error;
2065 }
2066 
2067 Error
2068 UserSettingsController::UpdateFileSpecOptionValue (const char *value,
2069                                                    VarSetOperationType op,
2070                                                    OptionValueFileSpec &option_value)
2071 {
2072     Error error;
2073     if (op == eVarSetOperationAssign)
2074     {
2075         option_value.GetCurrentValue().SetFile (value, false);
2076     }
2077     else if (op == eVarSetOperationAppend)
2078     {
2079         char path[PATH_MAX];
2080         if (option_value.GetCurrentValue().GetPath (path, sizeof(path)))
2081         {
2082             int path_len = ::strlen (path);
2083             int value_len = ::strlen (value);
2084             if (value_len + 1  > sizeof(path) - path_len)
2085             {
2086                 error.SetErrorString("path too long.");
2087             }
2088             else
2089             {
2090                 ::strncat (path, value, sizeof(path) - path_len - 1);
2091                 option_value.GetCurrentValue().SetFile (path, false);
2092             }
2093         }
2094         else
2095         {
2096             error.SetErrorString("path too long.");
2097         }
2098     }
2099     else if (op == eVarSetOperationClear)
2100     {
2101         option_value.Clear();
2102     }
2103     else
2104     {
2105         error.SetErrorString ("operation not supported for FileSpec option value type.");
2106     }
2107     return error;
2108 }
2109 
2110 
2111 void
2112 UserSettingsController::UpdateBooleanVariable (VarSetOperationType op,
2113                                                bool &bool_value,
2114                                                const char *value_cstr,
2115                                                bool clear_value,
2116                                                Error &err)
2117 {
2118     switch (op)
2119     {
2120     case eVarSetOperationReplace:
2121     case eVarSetOperationInsertBefore:
2122     case eVarSetOperationInsertAfter:
2123     case eVarSetOperationRemove:
2124     case eVarSetOperationAppend:
2125     case eVarSetOperationInvalid:
2126     default:
2127         err.SetErrorString ("invalid operation for Boolean variable, cannot update value");
2128         break;
2129 
2130     case eVarSetOperationClear:
2131         err.Clear();
2132         bool_value = clear_value;
2133         break;
2134 
2135     case eVarSetOperationAssign:
2136         {
2137             bool success = false;
2138 
2139 
2140             if (value_cstr == NULL)
2141                 err.SetErrorStringWithFormat ("invalid boolean string value (NULL)");
2142             else if (value_cstr[0] == '\0')
2143                 err.SetErrorStringWithFormat ("invalid boolean string value (empty)");
2144             else
2145             {
2146                 bool new_value = Args::StringToBoolean (value_cstr, false, &success);
2147                 if (success)
2148                 {
2149                     err.Clear();
2150                     bool_value = new_value;
2151                 }
2152                 else
2153                     err.SetErrorStringWithFormat ("invalid boolean string value: '%s'", value_cstr);
2154             }
2155         }
2156         break;
2157     }
2158 }
2159 Error
2160 UserSettingsController::UpdateBooleanOptionValue (const char *value,
2161                                                   VarSetOperationType op,
2162                                                   OptionValueBoolean &option_value)
2163 {
2164     Error error;
2165     switch (op)
2166     {
2167     case eVarSetOperationReplace:
2168     case eVarSetOperationInsertBefore:
2169     case eVarSetOperationInsertAfter:
2170     case eVarSetOperationRemove:
2171     case eVarSetOperationAppend:
2172     case eVarSetOperationInvalid:
2173     default:
2174         error.SetErrorString ("Invalid operation for Boolean variable.  Cannot update value.\n");
2175         break;
2176 
2177     case eVarSetOperationClear:
2178         option_value.Clear();
2179         break;
2180 
2181     case eVarSetOperationAssign:
2182         {
2183             bool success = false;
2184             error = option_value.SetValueFromCString(value);
2185 
2186             if (value == NULL)
2187                 error.SetErrorStringWithFormat ("invalid boolean string value (NULL)\n");
2188             else if (value[0] == '\0')
2189                 error.SetErrorStringWithFormat ("invalid boolean string value (empty)\n");
2190             else
2191             {
2192                 bool new_value = Args::StringToBoolean (value, false, &success);
2193                 if (success)
2194                 {
2195                     error.Clear();
2196                     option_value = new_value;
2197                 }
2198                 else
2199                     error.SetErrorStringWithFormat ("invalid boolean string value: '%s'\n", value);
2200             }
2201         }
2202         break;
2203     }
2204     return error;
2205 }
2206 
2207 void
2208 UserSettingsController::UpdateStringArrayVariable (VarSetOperationType op,
2209                                                    const char *index_value,
2210                                                    Args &array_var,
2211                                                    const char *new_value,
2212                                                    Error &err)
2213 {
2214     int index = -1;
2215     bool valid_index = true;
2216 
2217     if (index_value != NULL)
2218     {
2219         for (int i = 0; i < strlen(index_value); ++i)
2220             if (!isdigit (index_value[i]))
2221             {
2222                 valid_index = false;
2223                 err.SetErrorStringWithFormat ("'%s' is not a valid integer index, cannot update array value",
2224                                               index_value);
2225             }
2226 
2227         if (valid_index)
2228             index = atoi (index_value);
2229 
2230         if (index < 0
2231             || index >= array_var.GetArgumentCount())
2232         {
2233             valid_index = false;
2234             err.SetErrorStringWithFormat ("%d is outside the bounds of the specified array variable, "
2235                                           "cannot update array value", index);
2236         }
2237     }
2238 
2239     switch (op)
2240     {
2241         case eVarSetOperationAssign:
2242             array_var.SetCommandString (new_value);
2243             break;
2244         case eVarSetOperationReplace:
2245         {
2246             if (valid_index)
2247                 array_var.ReplaceArgumentAtIndex (index, new_value);
2248             break;
2249         }
2250         case eVarSetOperationInsertBefore:
2251         case eVarSetOperationInsertAfter:
2252         {
2253             if (valid_index)
2254             {
2255                 Args new_array (new_value);
2256                 if (op == eVarSetOperationInsertAfter)
2257                     ++index;
2258                 for (int i = 0; i < new_array.GetArgumentCount(); ++i)
2259                     array_var.InsertArgumentAtIndex (index, new_array.GetArgumentAtIndex (i));
2260             }
2261             break;
2262         }
2263         case eVarSetOperationRemove:
2264         {
2265             if (valid_index)
2266                 array_var.DeleteArgumentAtIndex (index);
2267             break;
2268         }
2269         case eVarSetOperationAppend:
2270         {
2271             Args new_array (new_value);
2272             array_var.AppendArguments (new_array);
2273             break;
2274         }
2275         case eVarSetOperationClear:
2276             array_var.Clear();
2277             break;
2278         default:
2279             err.SetErrorString ("unrecognized operation, cannot update value");
2280             break;
2281     }
2282 }
2283 
2284 void
2285 UserSettingsController::UpdateDictionaryVariable (VarSetOperationType op,
2286                                                   const char *index_value,
2287                                                   std::map<std::string, std::string> &dictionary,
2288                                                   const char *new_value,
2289                                                   Error &err)
2290 {
2291     switch (op)
2292     {
2293         case eVarSetOperationReplace:
2294             if (index_value != NULL)
2295             {
2296                 std::string key (index_value);
2297                 std::map<std::string, std::string>::iterator pos;
2298 
2299                 pos = dictionary.find (key);
2300                 if (pos != dictionary.end())
2301                     dictionary[key] = new_value;
2302                 else
2303                     err.SetErrorStringWithFormat ("'%s' is not an existing key; cannot replace value", index_value);
2304             }
2305             else
2306                 err.SetErrorString ("'settings replace' requires a key for dictionary variables, no key supplied");
2307             break;
2308         case eVarSetOperationRemove:
2309             if (index_value != NULL)
2310             {
2311                 std::string key (index_value);
2312                 dictionary.erase (key);
2313             }
2314             else
2315                 err.SetErrorString ("'settings remove' requires a key for dictionary variables, no key supplied");
2316             break;
2317         case eVarSetOperationClear:
2318             dictionary.clear ();
2319             break;
2320         case eVarSetOperationAppend:
2321         case eVarSetOperationAssign:
2322             {
2323                 // Clear the dictionary if it's an assign with new_value as NULL.
2324                 if (new_value == NULL && op == eVarSetOperationAssign)
2325                 {
2326                     dictionary.clear ();
2327                     break;
2328                 }
2329                 Args args (new_value);
2330                 size_t num_args = args.GetArgumentCount();
2331                 RegularExpression regex("(\\[\"?)?"                 // Regex match 1 (optional key prefix of '["' pr '[')
2332                                         "([A-Za-z_][A-Za-z_0-9]*)"  // Regex match 2 (key string)
2333                                         "(\"?\\])?"                 // Regex match 3 (optional key suffix of '"]' pr ']')
2334                                         "="                         // The equal sign that is required
2335                                         "(.*)");                    // Regex match 4 (value string)
2336                 std::string key, value;
2337 
2338                 for (size_t i = 0; i < num_args; ++i)
2339                 {
2340                     const char *key_equal_value_arg = args.GetArgumentAtIndex (i);
2341                     // Execute the regular expression on each arg.
2342                     if (regex.Execute(key_equal_value_arg, 5))
2343                     {
2344                         // The regular expression succeeded. The match at index
2345                         // zero will be the entire string that matched the entire
2346                         // regular expression. The match at index 1 - 4 will be
2347                         // as mentioned above by the creation of the regex pattern.
2348                         // Match index 2 is the key, match index 4 is the value.
2349                         regex.GetMatchAtIndex (key_equal_value_arg, 2, key);
2350                         regex.GetMatchAtIndex (key_equal_value_arg, 4, value);
2351                         dictionary[key] = value;
2352                     }
2353                     else
2354                     {
2355                         err.SetErrorString ("invalid format for dictionary value, expected one of '[\"<key>\"]=<value>', '[<key>]=<value>', or '<key>=<value>'");
2356                     }
2357                 }
2358             }
2359             break;
2360         case eVarSetOperationInsertBefore:
2361         case eVarSetOperationInsertAfter:
2362             err.SetErrorString ("specified operation cannot be performed on dictionary variables");
2363             break;
2364         default:
2365             err.SetErrorString ("unrecognized operation");
2366             break;
2367     }
2368 }
2369 
2370 const char *
2371 UserSettingsController::EnumToString (const OptionEnumValueElement *enum_values,
2372                                       int value)
2373 {
2374     int i = 0;
2375     while (enum_values[i].string_value != NULL)
2376     {
2377         if (enum_values[i].value == value)
2378             return enum_values[i].string_value;
2379         ++i;
2380     }
2381 
2382     return "";
2383 }
2384 
2385 
2386 void
2387 UserSettingsController::UpdateEnumVariable (OptionEnumValueElement *enum_values,
2388                                             int *enum_var,
2389                                             const char *new_value,
2390                                             Error &error)
2391 {
2392     *enum_var = Args::StringToOptionEnum (new_value, enum_values, enum_values[0].value, error);
2393 }
2394 
2395 void
2396 UserSettingsController::RenameInstanceSettings (const char *old_name, const char *new_name)
2397 {
2398     Mutex::Locker live_mutex (m_live_settings_mutex);
2399     Mutex::Locker pending_mutex (m_pending_settings_mutex);
2400     std::string old_name_key (old_name);
2401     std::string new_name_key (new_name);
2402 
2403     // First, find the live instance settings for the old_name.  If they don't exist in the live settings
2404     // list, then this is not a setting that can be renamed.
2405 
2406     if ((old_name_key[0] != '[') || (old_name_key[old_name_key.size() -1] != ']'))
2407     {
2408         StreamString tmp_str;
2409         tmp_str.Printf ("[%s]", old_name);
2410           old_name_key = tmp_str.GetData();
2411     }
2412 
2413     if ((new_name_key[0] != '[') || (new_name_key[new_name_key.size() -1] != ']'))
2414     {
2415         StreamString tmp_str;
2416         tmp_str.Printf ("[%s]", new_name);
2417         new_name_key = tmp_str.GetData();
2418     }
2419 
2420     if (old_name_key.compare (new_name_key) == 0)
2421         return;
2422 
2423     size_t len = new_name_key.length();
2424     std::string stripped_new_name = new_name_key.substr (1, len-2);  // new name without the '[ ]'
2425 
2426     InstanceSettingsMap::iterator pos;
2427 
2428     pos = m_live_settings.find (old_name_key);
2429     if (pos != m_live_settings.end())
2430     {
2431         InstanceSettings *live_settings = pos->second;
2432 
2433         // Rename the settings.
2434         live_settings->ChangeInstanceName (stripped_new_name);
2435 
2436         // Now see if there are any pending settings for the new name; if so, copy them into live_settings.
2437         std::map<std::string,  InstanceSettingsSP>::iterator pending_pos;
2438         pending_pos = m_pending_settings.find (new_name_key);
2439         if (pending_pos != m_pending_settings.end())
2440         {
2441             InstanceSettingsSP pending_settings_sp = pending_pos->second;
2442             live_settings->CopyInstanceSettings (pending_settings_sp, false);
2443         }
2444 
2445         // Erase the old entry (under the old name) from live settings.
2446         m_live_settings.erase (pos);
2447 
2448         // Add the new entry, with the new name, into live settings.
2449         m_live_settings[new_name_key] = live_settings;
2450     }
2451 }
2452 
2453 //----------------------------------------------------------------------
2454 // class InstanceSettings
2455 //----------------------------------------------------------------------
2456 
2457 InstanceSettings::InstanceSettings (UserSettingsController &owner, const char *instance_name, bool live_instance) :
2458     m_owner (owner),
2459     m_instance_name (instance_name)
2460 {
2461     if ((m_instance_name != InstanceSettings::GetDefaultName())
2462         && (m_instance_name !=  InstanceSettings::InvalidName())
2463         && live_instance)
2464         m_owner.RegisterInstanceSettings (this);
2465 }
2466 
2467 InstanceSettings::~InstanceSettings ()
2468 {
2469     if (m_instance_name != InstanceSettings::GetDefaultName())
2470         m_owner.UnregisterInstanceSettings (this);
2471 }
2472 
2473 const ConstString &
2474 InstanceSettings::GetDefaultName ()
2475 {
2476     static const ConstString g_default_settings_name ("[DEFAULT]");
2477 
2478     return g_default_settings_name;
2479 }
2480 
2481 const ConstString &
2482 InstanceSettings::InvalidName ()
2483 {
2484     static const ConstString g_invalid_name ("Invalid instance name");
2485 
2486     return g_invalid_name;
2487 }
2488 
2489 void
2490 InstanceSettings::ChangeInstanceName (const std::string &new_instance_name)
2491 {
2492     m_instance_name.SetCString (new_instance_name.c_str());
2493 }
2494 
2495 
2496