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