1ac7ddfbfSEd Maste //===-- OptionValuePathMappings.cpp -----------------------------*- C++ -*-===//
2ac7ddfbfSEd Maste //
3ac7ddfbfSEd Maste //                     The LLVM Compiler Infrastructure
4ac7ddfbfSEd Maste //
5ac7ddfbfSEd Maste // This file is distributed under the University of Illinois Open Source
6ac7ddfbfSEd Maste // License. See LICENSE.TXT for details.
7ac7ddfbfSEd Maste //
8ac7ddfbfSEd Maste //===----------------------------------------------------------------------===//
9ac7ddfbfSEd Maste 
10ac7ddfbfSEd Maste #include "lldb/Interpreter/OptionValuePathMappings.h"
11ac7ddfbfSEd Maste 
12*b5893f02SDimitry Andric #include "lldb/Host/FileSystem.h"
131c3bbb01SEd Maste #include "lldb/Host/StringConvert.h"
144ba319b5SDimitry Andric #include "lldb/Utility/Args.h"
15f678e45dSDimitry Andric #include "lldb/Utility/FileSpec.h"
16f678e45dSDimitry Andric #include "lldb/Utility/Stream.h"
17ac7ddfbfSEd Maste 
18ac7ddfbfSEd Maste using namespace lldb;
19ac7ddfbfSEd Maste using namespace lldb_private;
20435933ddSDimitry Andric namespace {
VerifyPathExists(const char * path)21435933ddSDimitry Andric static bool VerifyPathExists(const char *path) {
224bb0738eSEd Maste   if (path && path[0])
23*b5893f02SDimitry Andric     return FileSystem::Instance().Exists(path);
244bb0738eSEd Maste   else
254bb0738eSEd Maste     return false;
264bb0738eSEd Maste }
274bb0738eSEd Maste }
284bb0738eSEd Maste 
DumpValue(const ExecutionContext * exe_ctx,Stream & strm,uint32_t dump_mask)29435933ddSDimitry Andric void OptionValuePathMappings::DumpValue(const ExecutionContext *exe_ctx,
30435933ddSDimitry Andric                                         Stream &strm, uint32_t dump_mask) {
31ac7ddfbfSEd Maste   if (dump_mask & eDumpOptionType)
32ac7ddfbfSEd Maste     strm.Printf("(%s)", GetTypeAsCString());
33435933ddSDimitry Andric   if (dump_mask & eDumpOptionValue) {
34ac7ddfbfSEd Maste     if (dump_mask & eDumpOptionType)
35ac7ddfbfSEd Maste       strm.Printf(" =%s", (m_path_mappings.GetSize() > 0) ? "\n" : "");
36ac7ddfbfSEd Maste     m_path_mappings.Dump(&strm);
37ac7ddfbfSEd Maste   }
38ac7ddfbfSEd Maste }
39ac7ddfbfSEd Maste 
SetValueFromString(llvm::StringRef value,VarSetOperationType op)405517e702SDimitry Andric Status OptionValuePathMappings::SetValueFromString(llvm::StringRef value,
41435933ddSDimitry Andric                                                    VarSetOperationType op) {
425517e702SDimitry Andric   Status error;
43435933ddSDimitry Andric   Args args(value.str());
44ac7ddfbfSEd Maste   const size_t argc = args.GetArgumentCount();
45ac7ddfbfSEd Maste 
46435933ddSDimitry Andric   switch (op) {
47ac7ddfbfSEd Maste   case eVarSetOperationClear:
48ac7ddfbfSEd Maste     Clear();
497aa51b79SEd Maste     NotifyValueChanged();
50ac7ddfbfSEd Maste     break;
51ac7ddfbfSEd Maste 
52ac7ddfbfSEd Maste   case eVarSetOperationReplace:
53435933ddSDimitry Andric     // Must be at least one index + 1 pair of paths, and the pair count must be
54435933ddSDimitry Andric     // even
55435933ddSDimitry Andric     if (argc >= 3 && (((argc - 1) & 1) == 0)) {
56435933ddSDimitry Andric       uint32_t idx =
57435933ddSDimitry Andric           StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
58ac7ddfbfSEd Maste       const uint32_t count = m_path_mappings.GetSize();
59435933ddSDimitry Andric       if (idx > count) {
60435933ddSDimitry Andric         error.SetErrorStringWithFormat(
61435933ddSDimitry Andric             "invalid file list index %u, index must be 0 through %u", idx,
62435933ddSDimitry Andric             count);
63435933ddSDimitry Andric       } else {
644bb0738eSEd Maste         bool changed = false;
65435933ddSDimitry Andric         for (size_t i = 1; i < argc; i += 2, ++idx) {
664bb0738eSEd Maste           const char *orginal_path = args.GetArgumentAtIndex(i);
674bb0738eSEd Maste           const char *replace_path = args.GetArgumentAtIndex(i + 1);
68435933ddSDimitry Andric           if (VerifyPathExists(replace_path)) {
694bb0738eSEd Maste             ConstString a(orginal_path);
704bb0738eSEd Maste             ConstString b(replace_path);
71ac7ddfbfSEd Maste             if (!m_path_mappings.Replace(a, b, idx, m_notify_changes))
72ac7ddfbfSEd Maste               m_path_mappings.Append(a, b, m_notify_changes);
734bb0738eSEd Maste             changed = true;
74435933ddSDimitry Andric           } else {
75435933ddSDimitry Andric             error.SetErrorStringWithFormat(
76435933ddSDimitry Andric                 "the replacement path doesn't exist: \"%s\"", replace_path);
774bb0738eSEd Maste             break;
784bb0738eSEd Maste           }
794bb0738eSEd Maste         }
804bb0738eSEd Maste         if (changed)
817aa51b79SEd Maste           NotifyValueChanged();
82ac7ddfbfSEd Maste       }
83435933ddSDimitry Andric     } else {
84435933ddSDimitry Andric       error.SetErrorString("replace operation takes an array index followed by "
85435933ddSDimitry Andric                            "one or more path pairs");
86ac7ddfbfSEd Maste     }
87ac7ddfbfSEd Maste     break;
88ac7ddfbfSEd Maste 
89ac7ddfbfSEd Maste   case eVarSetOperationAssign:
90435933ddSDimitry Andric     if (argc < 2 || (argc & 1)) {
91ac7ddfbfSEd Maste       error.SetErrorString("assign operation takes one or more path pairs");
92ac7ddfbfSEd Maste       break;
93ac7ddfbfSEd Maste     }
94ac7ddfbfSEd Maste     m_path_mappings.Clear(m_notify_changes);
95ac7ddfbfSEd Maste     // Fall through to append case
964bb0738eSEd Maste     LLVM_FALLTHROUGH;
97ac7ddfbfSEd Maste   case eVarSetOperationAppend:
98435933ddSDimitry Andric     if (argc < 2 || (argc & 1)) {
99ac7ddfbfSEd Maste       error.SetErrorString("append operation takes one or more path pairs");
100ac7ddfbfSEd Maste       break;
101435933ddSDimitry Andric     } else {
1024bb0738eSEd Maste       bool changed = false;
103435933ddSDimitry Andric       for (size_t i = 0; i < argc; i += 2) {
1044bb0738eSEd Maste         const char *orginal_path = args.GetArgumentAtIndex(i);
1054bb0738eSEd Maste         const char *replace_path = args.GetArgumentAtIndex(i + 1);
106435933ddSDimitry Andric         if (VerifyPathExists(replace_path)) {
1074bb0738eSEd Maste           ConstString a(orginal_path);
1084bb0738eSEd Maste           ConstString b(replace_path);
109ac7ddfbfSEd Maste           m_path_mappings.Append(a, b, m_notify_changes);
110ac7ddfbfSEd Maste           m_value_was_set = true;
1114bb0738eSEd Maste           changed = true;
112435933ddSDimitry Andric         } else {
113435933ddSDimitry Andric           error.SetErrorStringWithFormat(
114435933ddSDimitry Andric               "the replacement path doesn't exist: \"%s\"", replace_path);
1154bb0738eSEd Maste           break;
1164bb0738eSEd Maste         }
1174bb0738eSEd Maste       }
1184bb0738eSEd Maste       if (changed)
1197aa51b79SEd Maste         NotifyValueChanged();
120ac7ddfbfSEd Maste     }
121ac7ddfbfSEd Maste     break;
122ac7ddfbfSEd Maste 
123ac7ddfbfSEd Maste   case eVarSetOperationInsertBefore:
124ac7ddfbfSEd Maste   case eVarSetOperationInsertAfter:
125435933ddSDimitry Andric     // Must be at least one index + 1 pair of paths, and the pair count must be
126435933ddSDimitry Andric     // even
127435933ddSDimitry Andric     if (argc >= 3 && (((argc - 1) & 1) == 0)) {
128435933ddSDimitry Andric       uint32_t idx =
129435933ddSDimitry Andric           StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
130ac7ddfbfSEd Maste       const uint32_t count = m_path_mappings.GetSize();
131435933ddSDimitry Andric       if (idx > count) {
132435933ddSDimitry Andric         error.SetErrorStringWithFormat(
133435933ddSDimitry Andric             "invalid file list index %u, index must be 0 through %u", idx,
134435933ddSDimitry Andric             count);
135435933ddSDimitry Andric       } else {
1364bb0738eSEd Maste         bool changed = false;
137ac7ddfbfSEd Maste         if (op == eVarSetOperationInsertAfter)
138ac7ddfbfSEd Maste           ++idx;
139435933ddSDimitry Andric         for (size_t i = 1; i < argc; i += 2, ++idx) {
1404bb0738eSEd Maste           const char *orginal_path = args.GetArgumentAtIndex(i);
1414bb0738eSEd Maste           const char *replace_path = args.GetArgumentAtIndex(i + 1);
142435933ddSDimitry Andric           if (VerifyPathExists(replace_path)) {
1434bb0738eSEd Maste             ConstString a(orginal_path);
1444bb0738eSEd Maste             ConstString b(replace_path);
145ac7ddfbfSEd Maste             m_path_mappings.Insert(a, b, idx, m_notify_changes);
1464bb0738eSEd Maste             changed = true;
147435933ddSDimitry Andric           } else {
148435933ddSDimitry Andric             error.SetErrorStringWithFormat(
149435933ddSDimitry Andric                 "the replacement path doesn't exist: \"%s\"", replace_path);
1504bb0738eSEd Maste             break;
1514bb0738eSEd Maste           }
1524bb0738eSEd Maste         }
1534bb0738eSEd Maste         if (changed)
1547aa51b79SEd Maste           NotifyValueChanged();
155ac7ddfbfSEd Maste       }
156435933ddSDimitry Andric     } else {
157435933ddSDimitry Andric       error.SetErrorString("insert operation takes an array index followed by "
158435933ddSDimitry Andric                            "one or more path pairs");
159ac7ddfbfSEd Maste     }
160ac7ddfbfSEd Maste     break;
161ac7ddfbfSEd Maste 
162ac7ddfbfSEd Maste   case eVarSetOperationRemove:
163435933ddSDimitry Andric     if (argc > 0) {
164ac7ddfbfSEd Maste       std::vector<int> remove_indexes;
165ac7ddfbfSEd Maste       bool all_indexes_valid = true;
166ac7ddfbfSEd Maste       size_t i;
167435933ddSDimitry Andric       for (i = 0; all_indexes_valid && i < argc; ++i) {
168435933ddSDimitry Andric         const int idx =
169435933ddSDimitry Andric             StringConvert::ToSInt32(args.GetArgumentAtIndex(i), INT32_MAX);
170ac7ddfbfSEd Maste         if (idx == INT32_MAX)
171ac7ddfbfSEd Maste           all_indexes_valid = false;
172ac7ddfbfSEd Maste         else
173ac7ddfbfSEd Maste           remove_indexes.push_back(idx);
174ac7ddfbfSEd Maste       }
175ac7ddfbfSEd Maste 
176435933ddSDimitry Andric       if (all_indexes_valid) {
177ac7ddfbfSEd Maste         size_t num_remove_indexes = remove_indexes.size();
178435933ddSDimitry Andric         if (num_remove_indexes) {
179ac7ddfbfSEd Maste           // Sort and then erase in reverse so indexes are always valid
180*b5893f02SDimitry Andric           llvm::sort(remove_indexes.begin(), remove_indexes.end());
181435933ddSDimitry Andric           for (size_t j = num_remove_indexes - 1; j < num_remove_indexes; ++j) {
182ac7ddfbfSEd Maste             m_path_mappings.Remove(j, m_notify_changes);
183ac7ddfbfSEd Maste           }
184ac7ddfbfSEd Maste         }
1857aa51b79SEd Maste         NotifyValueChanged();
186435933ddSDimitry Andric       } else {
187435933ddSDimitry Andric         error.SetErrorStringWithFormat(
188435933ddSDimitry Andric             "invalid array index '%s', aborting remove operation",
189435933ddSDimitry Andric             args.GetArgumentAtIndex(i));
190ac7ddfbfSEd Maste       }
191435933ddSDimitry Andric     } else {
192ac7ddfbfSEd Maste       error.SetErrorString("remove operation takes one or more array index");
193ac7ddfbfSEd Maste     }
194ac7ddfbfSEd Maste     break;
195ac7ddfbfSEd Maste 
196ac7ddfbfSEd Maste   case eVarSetOperationInvalid:
1971c3bbb01SEd Maste     error = OptionValue::SetValueFromString(value, op);
198ac7ddfbfSEd Maste     break;
199ac7ddfbfSEd Maste   }
200ac7ddfbfSEd Maste   return error;
201ac7ddfbfSEd Maste }
202ac7ddfbfSEd Maste 
DeepCopy() const203435933ddSDimitry Andric lldb::OptionValueSP OptionValuePathMappings::DeepCopy() const {
204ac7ddfbfSEd Maste   return OptionValueSP(new OptionValuePathMappings(*this));
205ac7ddfbfSEd Maste }
206