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