1//===-- OptionValueProperties.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 "lldb/Interpreter/OptionValueProperties.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/Core/Flags.h"
17#include "lldb/Core/Stream.h"
18#include "lldb/Core/StringList.h"
19#include "lldb/Core/UserSettingsController.h"
20#include "lldb/Interpreter/Args.h"
21#include "lldb/Interpreter/OptionValues.h"
22#include "lldb/Interpreter/Property.h"
23
24using namespace lldb;
25using namespace lldb_private;
26
27
28OptionValueProperties::OptionValueProperties (const ConstString &name) :
29    OptionValue (),
30    m_name (name),
31    m_properties (),
32    m_name_to_index ()
33{
34}
35
36OptionValueProperties::OptionValueProperties (const OptionValueProperties &global_properties) :
37    OptionValue (global_properties),
38    m_name (global_properties.m_name),
39    m_properties (global_properties.m_properties),
40    m_name_to_index (global_properties.m_name_to_index)
41{
42    // We now have an exact copy of "global_properties". We need to now
43    // find all non-global settings and copy the property values so that
44    // all non-global settings get new OptionValue instances created for
45    // them.
46    const size_t num_properties = m_properties.size();
47    for (size_t i=0; i<num_properties; ++i)
48    {
49        // Duplicate any values that are not global when contructing properties from
50        // a global copy
51        if (m_properties[i].IsGlobal() == false)
52        {
53            lldb::OptionValueSP new_value_sp (m_properties[i].GetValue()->DeepCopy());
54            m_properties[i].SetOptionValue(new_value_sp);
55        }
56    }
57}
58
59
60
61size_t
62OptionValueProperties::GetNumProperties() const
63{
64    return m_properties.size();
65}
66
67
68void
69OptionValueProperties::Initialize (const PropertyDefinition *defs)
70{
71    for (size_t i=0; defs[i].name; ++i)
72    {
73        Property property(defs[i]);
74        assert(property.IsValid());
75        m_name_to_index.Append(property.GetName().GetCString(),m_properties.size());
76        property.GetValue()->SetParent(shared_from_this());
77        m_properties.push_back(property);
78    }
79    m_name_to_index.Sort();
80}
81
82void
83OptionValueProperties::AppendProperty(const ConstString &name,
84                                      const ConstString &desc,
85                                      bool is_global,
86                                      const OptionValueSP &value_sp)
87{
88    Property property(name, desc, is_global, value_sp);
89    m_name_to_index.Append(name.GetCString(),m_properties.size());
90    m_properties.push_back(property);
91    value_sp->SetParent (shared_from_this());
92    m_name_to_index.Sort();
93}
94
95
96
97//bool
98//OptionValueProperties::GetQualifiedName (Stream &strm)
99//{
100//    bool dumped_something = false;
101////    lldb::OptionValuePropertiesSP parent_sp(GetParent ());
102////    if (parent_sp)
103////    {
104////        parent_sp->GetQualifiedName (strm);
105////        strm.PutChar('.');
106////        dumped_something = true;
107////    }
108//    if (m_name)
109//    {
110//        strm << m_name;
111//        dumped_something = true;
112//    }
113//    return dumped_something;
114//}
115//
116lldb::OptionValueSP
117OptionValueProperties::GetValueForKey  (const ExecutionContext *exe_ctx,
118                                        const ConstString &key,
119                                        bool will_modify) const
120{
121    lldb::OptionValueSP value_sp;
122    size_t idx = m_name_to_index.Find (key.GetCString(), SIZE_MAX);
123    if (idx < m_properties.size())
124        value_sp = GetPropertyAtIndex(exe_ctx, will_modify, idx)->GetValue();
125    return value_sp;
126}
127
128lldb::OptionValueSP
129OptionValueProperties::GetSubValue (const ExecutionContext *exe_ctx,
130                                    const char *name,
131                                    bool will_modify,
132                                    Error &error) const
133{
134    lldb::OptionValueSP value_sp;
135
136    if (name && name[0])
137    {
138        const char *sub_name = NULL;
139        ConstString key;
140        size_t key_len = ::strcspn (name, ".[{");
141
142        if (name[key_len])
143        {
144            key.SetCStringWithLength (name, key_len);
145            sub_name = name + key_len;
146        }
147        else
148            key.SetCString (name);
149
150        value_sp = GetValueForKey (exe_ctx, key, will_modify);
151        if (sub_name && value_sp)
152        {
153            switch (sub_name[0])
154            {
155            case '.':
156                return value_sp->GetSubValue (exe_ctx, sub_name + 1, will_modify, error);
157
158            case '{':
159                // Predicate matching for predicates like
160                // "<setting-name>{<predicate>}"
161                // strings are parsed by the current OptionValueProperties subclass
162                // to mean whatever they want to. For instance a subclass of
163                // OptionValueProperties for a lldb_private::Target might implement:
164                // "target.run-args{arch==i386}"   -- only set run args if the arch is i386
165                // "target.run-args{path=/tmp/a/b/c/a.out}" -- only set run args if the path matches
166                // "target.run-args{basename==test&&arch==x86_64}" -- only set run args if exectable basename is "test" and arch is "x86_64"
167                if (sub_name[1])
168                {
169                    const char *predicate_start = sub_name + 1;
170                    const char *predicate_end = strchr(predicate_start, '}');
171                    if (predicate_end)
172                    {
173                        std::string predicate(predicate_start, predicate_end);
174                        if (PredicateMatches(exe_ctx, predicate.c_str()))
175                        {
176                            if (predicate_end[1])
177                            {
178                                // Still more subvalue string to evaluate
179                                return value_sp->GetSubValue (exe_ctx, predicate_end + 1, will_modify, error);
180                            }
181                            else
182                            {
183                                // We have a match!
184                                break;
185                            }
186                        }
187                    }
188                }
189                // Predicate didn't match or wasn't correctly formed
190                value_sp.reset();
191                break;
192
193            case '[':
194                // Array or dictionary access for subvalues like:
195                // "[12]"       -- access 12th array element
196                // "['hello']"  -- dictionary access of key named hello
197                return value_sp->GetSubValue (exe_ctx, sub_name, will_modify, error);
198
199            default:
200                value_sp.reset();
201                break;
202            }
203        }
204    }
205    return value_sp;
206}
207
208Error
209OptionValueProperties::SetSubValue (const ExecutionContext *exe_ctx,
210                                    VarSetOperationType op,
211                                    const char *name,
212                                    const char *value)
213{
214    Error error;
215    const bool will_modify = true;
216    lldb::OptionValueSP value_sp (GetSubValue (exe_ctx, name, will_modify, error));
217    if (value_sp)
218        error = value_sp->SetValueFromCString(value, op);
219    else
220    {
221        if (error.AsCString() == NULL)
222            error.SetErrorStringWithFormat("invalid value path '%s'", name);
223    }
224    return error;
225}
226
227
228ConstString
229OptionValueProperties::GetPropertyNameAtIndex (uint32_t idx) const
230{
231    const Property *property = GetPropertyAtIndex(NULL, false, idx);
232    if (property)
233        return property->GetName();
234    return ConstString();
235
236}
237
238const char *
239OptionValueProperties::GetPropertyDescriptionAtIndex (uint32_t idx) const
240{
241    const Property *property = GetPropertyAtIndex(NULL, false, idx);
242    if (property)
243        return property->GetDescription();
244    return NULL;
245}
246
247uint32_t
248OptionValueProperties::GetPropertyIndex (const ConstString &name) const
249{
250    return m_name_to_index.Find (name.GetCString(), SIZE_MAX);
251}
252
253const Property *
254OptionValueProperties::GetProperty (const ExecutionContext *exe_ctx, bool will_modify, const ConstString &name) const
255{
256    return GetPropertyAtIndex (exe_ctx, will_modify, m_name_to_index.Find (name.GetCString(), SIZE_MAX));
257}
258
259const Property *
260OptionValueProperties::GetPropertyAtIndex (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
261{
262    return ProtectedGetPropertyAtIndex (idx);
263}
264
265lldb::OptionValueSP
266OptionValueProperties::GetPropertyValueAtIndex (const ExecutionContext *exe_ctx,
267                                                bool will_modify,
268                                                uint32_t idx) const
269{
270    const Property *setting = GetPropertyAtIndex (exe_ctx, will_modify, idx);
271    if (setting)
272        return setting->GetValue();
273    return OptionValueSP();
274}
275
276OptionValuePathMappings *
277OptionValueProperties::GetPropertyAtIndexAsOptionValuePathMappings (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
278{
279    OptionValueSP value_sp(GetPropertyValueAtIndex (exe_ctx, will_modify, idx));
280    if (value_sp)
281        return value_sp->GetAsPathMappings();
282    return NULL;
283}
284
285OptionValueFileSpecList *
286OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpecList (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
287{
288    OptionValueSP value_sp(GetPropertyValueAtIndex (exe_ctx, will_modify, idx));
289    if (value_sp)
290        return value_sp->GetAsFileSpecList();
291    return NULL;
292}
293
294OptionValueArch *
295OptionValueProperties::GetPropertyAtIndexAsOptionValueArch (const ExecutionContext *exe_ctx, uint32_t idx) const
296{
297    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
298    if (property)
299        return property->GetValue()->GetAsArch();
300    return NULL;
301}
302
303bool
304OptionValueProperties::GetPropertyAtIndexAsArgs (const ExecutionContext *exe_ctx, uint32_t idx, Args &args) const
305{
306    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
307    if (property)
308    {
309        OptionValue *value = property->GetValue().get();
310        if (value)
311        {
312            const OptionValueArray *array = value->GetAsArray();
313            if (array)
314                return array->GetArgs(args);
315            else
316            {
317                const OptionValueDictionary *dict = value->GetAsDictionary();
318                if (dict)
319                    return dict->GetArgs(args);
320            }
321        }
322    }
323    return false;
324}
325
326bool
327OptionValueProperties::SetPropertyAtIndexFromArgs (const ExecutionContext *exe_ctx, uint32_t idx, const Args &args)
328{
329    const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
330    if (property)
331    {
332        OptionValue *value = property->GetValue().get();
333        if (value)
334        {
335            OptionValueArray *array = value->GetAsArray();
336            if (array)
337                return array->SetArgs(args, eVarSetOperationAssign).Success();
338            else
339            {
340                OptionValueDictionary *dict = value->GetAsDictionary();
341                if (dict)
342                    return dict->SetArgs(args, eVarSetOperationAssign).Success();
343            }
344        }
345    }
346    return false;
347}
348
349bool
350OptionValueProperties::GetPropertyAtIndexAsBoolean (const ExecutionContext *exe_ctx, uint32_t idx, bool fail_value) const
351{
352    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
353    if (property)
354    {
355        OptionValue *value = property->GetValue().get();
356        if (value)
357            return value->GetBooleanValue(fail_value);
358    }
359    return fail_value;
360}
361
362bool
363OptionValueProperties::SetPropertyAtIndexAsBoolean (const ExecutionContext *exe_ctx, uint32_t idx, bool new_value)
364{
365    const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
366    if (property)
367    {
368        OptionValue *value = property->GetValue().get();
369        if (value)
370        {
371            value->SetBooleanValue(new_value);
372            return true;
373        }
374    }
375    return false;
376}
377
378OptionValueDictionary *
379OptionValueProperties::GetPropertyAtIndexAsOptionValueDictionary (const ExecutionContext *exe_ctx, uint32_t idx) const
380{
381    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
382    if (property)
383        return property->GetValue()->GetAsDictionary();
384    return NULL;
385}
386
387int64_t
388OptionValueProperties::GetPropertyAtIndexAsEnumeration (const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) const
389{
390    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
391    if (property)
392    {
393        OptionValue *value = property->GetValue().get();
394        if (value)
395            return value->GetEnumerationValue(fail_value);
396    }
397    return fail_value;
398}
399
400bool
401OptionValueProperties::SetPropertyAtIndexAsEnumeration (const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value)
402{
403    const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
404    if (property)
405    {
406        OptionValue *value = property->GetValue().get();
407        if (value)
408            return value->SetEnumerationValue(new_value);
409    }
410    return false;
411}
412
413
414OptionValueFileSpec *
415OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpec (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
416{
417    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
418    if (property)
419    {
420        OptionValue *value = property->GetValue().get();
421        if (value)
422            return value->GetAsFileSpec();
423    }
424    return NULL;
425}
426
427
428FileSpec
429OptionValueProperties::GetPropertyAtIndexAsFileSpec (const ExecutionContext *exe_ctx, uint32_t idx) const
430{
431    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
432    if (property)
433    {
434        OptionValue *value = property->GetValue().get();
435        if (value)
436            return value->GetFileSpecValue();
437    }
438    return FileSpec();
439}
440
441
442bool
443OptionValueProperties::SetPropertyAtIndexAsFileSpec (const ExecutionContext *exe_ctx, uint32_t idx, const FileSpec &new_file_spec)
444{
445    const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
446    if (property)
447    {
448        OptionValue *value = property->GetValue().get();
449        if (value)
450            return value->SetFileSpecValue(new_file_spec);
451    }
452    return false;
453}
454
455const RegularExpression *
456OptionValueProperties::GetPropertyAtIndexAsOptionValueRegex (const ExecutionContext *exe_ctx, uint32_t idx) const
457{
458    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
459    if (property)
460    {
461        OptionValue *value = property->GetValue().get();
462        if (value)
463            return value->GetRegexValue();
464    }
465    return NULL;
466}
467
468OptionValueSInt64 *
469OptionValueProperties::GetPropertyAtIndexAsOptionValueSInt64 (const ExecutionContext *exe_ctx, uint32_t idx) const
470{
471    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
472    if (property)
473    {
474        OptionValue *value = property->GetValue().get();
475        if (value)
476            return value->GetAsSInt64();
477    }
478    return NULL;
479}
480
481int64_t
482OptionValueProperties::GetPropertyAtIndexAsSInt64 (const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) const
483{
484    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
485    if (property)
486    {
487        OptionValue *value = property->GetValue().get();
488        if (value)
489            return value->GetSInt64Value(fail_value);
490    }
491    return fail_value;
492}
493
494bool
495OptionValueProperties::SetPropertyAtIndexAsSInt64 (const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value)
496{
497    const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
498    if (property)
499    {
500        OptionValue *value = property->GetValue().get();
501        if (value)
502            return value->SetSInt64Value(new_value);
503    }
504    return false;
505}
506
507const char *
508OptionValueProperties::GetPropertyAtIndexAsString (const ExecutionContext *exe_ctx, uint32_t idx, const char *fail_value) const
509{
510    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
511    if (property)
512    {
513        OptionValue *value = property->GetValue().get();
514        if (value)
515            return value->GetStringValue(fail_value);
516    }
517    return fail_value;
518}
519
520bool
521OptionValueProperties::SetPropertyAtIndexAsString (const ExecutionContext *exe_ctx, uint32_t idx, const char *new_value)
522{
523    const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
524    if (property)
525    {
526        OptionValue *value = property->GetValue().get();
527        if (value)
528            return value->SetStringValue(new_value);
529    }
530    return false;
531}
532
533OptionValueString *
534OptionValueProperties::GetPropertyAtIndexAsOptionValueString (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
535{
536    OptionValueSP value_sp(GetPropertyValueAtIndex (exe_ctx, will_modify, idx));
537    if (value_sp)
538        return value_sp->GetAsString();
539    return NULL;
540}
541
542
543uint64_t
544OptionValueProperties::GetPropertyAtIndexAsUInt64 (const ExecutionContext *exe_ctx, uint32_t idx, uint64_t fail_value) const
545{
546    const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
547    if (property)
548    {
549        OptionValue *value = property->GetValue().get();
550        if (value)
551            return value->GetUInt64Value(fail_value);
552    }
553    return fail_value;
554}
555
556bool
557OptionValueProperties::SetPropertyAtIndexAsUInt64 (const ExecutionContext *exe_ctx, uint32_t idx, uint64_t new_value)
558{
559    const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
560    if (property)
561    {
562        OptionValue *value = property->GetValue().get();
563        if (value)
564            return value->SetUInt64Value(new_value);
565    }
566    return false;
567}
568
569bool
570OptionValueProperties::Clear ()
571{
572    const size_t num_properties = m_properties.size();
573    for (size_t i=0; i<num_properties; ++i)
574        m_properties[i].GetValue()->Clear();
575    return true;
576}
577
578
579Error
580OptionValueProperties::SetValueFromCString (const char *value, VarSetOperationType op)
581{
582    Error error;
583
584//    Args args(value_cstr);
585//    const size_t argc = args.GetArgumentCount();
586    switch (op)
587    {
588        case eVarSetOperationClear:
589            Clear ();
590            break;
591
592        case eVarSetOperationReplace:
593        case eVarSetOperationAssign:
594        case eVarSetOperationRemove:
595        case eVarSetOperationInsertBefore:
596        case eVarSetOperationInsertAfter:
597        case eVarSetOperationAppend:
598        case eVarSetOperationInvalid:
599            error = OptionValue::SetValueFromCString (value, op);
600            break;
601    }
602
603    return error;
604}
605
606void
607OptionValueProperties::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)
608{
609    const size_t num_properties = m_properties.size();
610    for (size_t i=0; i<num_properties; ++i)
611    {
612        const Property *property = GetPropertyAtIndex(exe_ctx, false, i);
613        if (property)
614        {
615            OptionValue *option_value = property->GetValue().get();
616            assert (option_value);
617            const bool transparent_value = option_value->ValueIsTransparent ();
618            property->Dump (exe_ctx,
619                            strm,
620                            dump_mask);
621            if (!transparent_value)
622                strm.EOL();
623        }
624    }
625}
626
627Error
628OptionValueProperties::DumpPropertyValue (const ExecutionContext *exe_ctx,
629                                          Stream &strm,
630                                          const char *property_path,
631                                          uint32_t dump_mask)
632{
633    Error error;
634    const bool will_modify = false;
635    lldb::OptionValueSP value_sp (GetSubValue (exe_ctx, property_path, will_modify, error));
636    if (value_sp)
637    {
638        if (!value_sp->ValueIsTransparent ())
639        {
640            if (dump_mask & eDumpOptionName)
641                strm.PutCString (property_path);
642            if (dump_mask & ~eDumpOptionName)
643                strm.PutChar (' ');
644        }
645        value_sp->DumpValue (exe_ctx, strm, dump_mask);
646    }
647    return error;
648}
649
650lldb::OptionValueSP
651OptionValueProperties::DeepCopy () const
652{
653    assert(!"this shouldn't happen");
654}
655
656const Property *
657OptionValueProperties::GetPropertyAtPath (const ExecutionContext *exe_ctx,
658                                          bool will_modify,
659                                          const char *name) const
660{
661    const Property *property = NULL;
662    if (name && name[0])
663    {
664        const char *sub_name = NULL;
665        ConstString key;
666        size_t key_len = ::strcspn (name, ".[{");
667
668        if (name[key_len])
669        {
670            key.SetCStringWithLength (name, key_len);
671            sub_name = name + key_len;
672        }
673        else
674            key.SetCString (name);
675
676        property = GetProperty (exe_ctx, will_modify, key);
677        if (sub_name && property)
678        {
679            if (sub_name[0] == '.')
680            {
681                OptionValueProperties *sub_properties = property->GetValue()->GetAsProperties();
682                if (sub_properties)
683                    return sub_properties->GetPropertyAtPath(exe_ctx, will_modify, sub_name + 1);
684            }
685            property = NULL;
686        }
687    }
688    return property;
689}
690
691void
692OptionValueProperties::DumpAllDescriptions (CommandInterpreter &interpreter,
693                                            Stream &strm) const
694{
695    size_t max_name_len = 0;
696    const size_t num_properties = m_properties.size();
697    for (size_t i=0; i<num_properties; ++i)
698    {
699        const Property *property = ProtectedGetPropertyAtIndex(i);
700        if (property)
701            max_name_len = std::max<size_t>(property->GetName().GetLength(), max_name_len);
702    }
703    for (size_t i=0; i<num_properties; ++i)
704    {
705        const Property *property = ProtectedGetPropertyAtIndex(i);
706        if (property)
707            property->DumpDescription (interpreter, strm, max_name_len, false);
708    }
709}
710
711void
712OptionValueProperties::Apropos (const char *keyword, std::vector<const Property *> &matching_properties) const
713{
714    const size_t num_properties = m_properties.size();
715    StreamString strm;
716    for (size_t i=0; i<num_properties; ++i)
717    {
718        const Property *property = ProtectedGetPropertyAtIndex(i);
719        if (property)
720        {
721            const OptionValueProperties *properties = property->GetValue()->GetAsProperties();
722            if (properties)
723            {
724                properties->Apropos (keyword, matching_properties);
725            }
726            else
727            {
728                bool match = false;
729                const char *name = property->GetName().GetCString();
730                if (name && ::strcasestr(name, keyword))
731                    match = true;
732                else
733                {
734                    const char *desc = property->GetDescription();
735                    if (desc && ::strcasestr(desc, keyword))
736                        match = true;
737                }
738                if (match)
739                {
740                    matching_properties.push_back (property);
741                }
742            }
743        }
744    }
745}
746
747lldb::OptionValuePropertiesSP
748OptionValueProperties::GetSubProperty (const ExecutionContext *exe_ctx,
749                                       const ConstString &name)
750{
751    lldb::OptionValueSP option_value_sp(GetValueForKey(exe_ctx, name, false));
752    if (option_value_sp)
753    {
754        OptionValueProperties *ov_properties = option_value_sp->GetAsProperties ();
755        if (ov_properties)
756            return ov_properties->shared_from_this();
757    }
758    return lldb::OptionValuePropertiesSP();
759}
760
761
762
763