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