167cc0636SGreg Clayton //===-- OptionValuePathMappings.cpp -----------------------------*- C++ -*-===//
267cc0636SGreg Clayton //
367cc0636SGreg Clayton //                     The LLVM Compiler Infrastructure
467cc0636SGreg Clayton //
567cc0636SGreg Clayton // This file is distributed under the University of Illinois Open Source
667cc0636SGreg Clayton // License. See LICENSE.TXT for details.
767cc0636SGreg Clayton //
867cc0636SGreg Clayton //===----------------------------------------------------------------------===//
967cc0636SGreg Clayton 
1067cc0636SGreg Clayton #include "lldb/Interpreter/OptionValuePathMappings.h"
1167cc0636SGreg Clayton 
1267cc0636SGreg Clayton // C Includes
1367cc0636SGreg Clayton // C++ Includes
1467cc0636SGreg Clayton // Other libraries and framework includes
1567cc0636SGreg Clayton // Project includes
16*dbd7fabaSJonas Devlieghere #include "lldb/Host/FileSystem.h"
175275aaa0SVince Harron #include "lldb/Host/StringConvert.h"
18145d95c9SPavel Labath #include "lldb/Utility/Args.h"
195713a05bSZachary Turner #include "lldb/Utility/FileSpec.h"
20bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
2167cc0636SGreg Clayton 
2267cc0636SGreg Clayton using namespace lldb;
2367cc0636SGreg Clayton using namespace lldb_private;
24b9c1b51eSKate Stone namespace {
25b9c1b51eSKate Stone static bool VerifyPathExists(const char *path) {
266a311641SGreg Clayton   if (path && path[0])
27*dbd7fabaSJonas Devlieghere     return FileSystem::Instance().Exists(path);
286a311641SGreg Clayton   else
296a311641SGreg Clayton     return false;
306a311641SGreg Clayton }
316a311641SGreg Clayton }
326a311641SGreg Clayton 
33b9c1b51eSKate Stone void OptionValuePathMappings::DumpValue(const ExecutionContext *exe_ctx,
34b9c1b51eSKate Stone                                         Stream &strm, uint32_t dump_mask) {
3567cc0636SGreg Clayton   if (dump_mask & eDumpOptionType)
3667cc0636SGreg Clayton     strm.Printf("(%s)", GetTypeAsCString());
37b9c1b51eSKate Stone   if (dump_mask & eDumpOptionValue) {
3867cc0636SGreg Clayton     if (dump_mask & eDumpOptionType)
3967cc0636SGreg Clayton       strm.Printf(" =%s", (m_path_mappings.GetSize() > 0) ? "\n" : "");
4067cc0636SGreg Clayton     m_path_mappings.Dump(&strm);
4167cc0636SGreg Clayton   }
4267cc0636SGreg Clayton }
4367cc0636SGreg Clayton 
4497206d57SZachary Turner Status OptionValuePathMappings::SetValueFromString(llvm::StringRef value,
45b9c1b51eSKate Stone                                                    VarSetOperationType op) {
4697206d57SZachary Turner   Status error;
47771ef6d4SMalcolm Parsons   Args args(value.str());
4867cc0636SGreg Clayton   const size_t argc = args.GetArgumentCount();
4967cc0636SGreg Clayton 
50b9c1b51eSKate Stone   switch (op) {
5167cc0636SGreg Clayton   case eVarSetOperationClear:
5267cc0636SGreg Clayton     Clear();
53332e8b1cSGreg Clayton     NotifyValueChanged();
5467cc0636SGreg Clayton     break;
5567cc0636SGreg Clayton 
5667cc0636SGreg Clayton   case eVarSetOperationReplace:
57b9c1b51eSKate Stone     // Must be at least one index + 1 pair of paths, and the pair count must be
58b9c1b51eSKate Stone     // even
59b9c1b51eSKate Stone     if (argc >= 3 && (((argc - 1) & 1) == 0)) {
60b9c1b51eSKate Stone       uint32_t idx =
61b9c1b51eSKate Stone           StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
6267cc0636SGreg Clayton       const uint32_t count = m_path_mappings.GetSize();
63b9c1b51eSKate Stone       if (idx > count) {
64b9c1b51eSKate Stone         error.SetErrorStringWithFormat(
65b9c1b51eSKate Stone             "invalid file list index %u, index must be 0 through %u", idx,
66b9c1b51eSKate Stone             count);
67b9c1b51eSKate Stone       } else {
686a311641SGreg Clayton         bool changed = false;
69b9c1b51eSKate Stone         for (size_t i = 1; i < argc; i += 2, ++idx) {
706a311641SGreg Clayton           const char *orginal_path = args.GetArgumentAtIndex(i);
716a311641SGreg Clayton           const char *replace_path = args.GetArgumentAtIndex(i + 1);
72b9c1b51eSKate Stone           if (VerifyPathExists(replace_path)) {
736a311641SGreg Clayton             ConstString a(orginal_path);
746a311641SGreg Clayton             ConstString b(replace_path);
7567cc0636SGreg Clayton             if (!m_path_mappings.Replace(a, b, idx, m_notify_changes))
7667cc0636SGreg Clayton               m_path_mappings.Append(a, b, m_notify_changes);
776a311641SGreg Clayton             changed = true;
78b9c1b51eSKate Stone           } else {
79b9c1b51eSKate Stone             error.SetErrorStringWithFormat(
80b9c1b51eSKate Stone                 "the replacement path doesn't exist: \"%s\"", replace_path);
816a311641SGreg Clayton             break;
826a311641SGreg Clayton           }
836a311641SGreg Clayton         }
846a311641SGreg Clayton         if (changed)
85332e8b1cSGreg Clayton           NotifyValueChanged();
8667cc0636SGreg Clayton       }
87b9c1b51eSKate Stone     } else {
88b9c1b51eSKate Stone       error.SetErrorString("replace operation takes an array index followed by "
89b9c1b51eSKate Stone                            "one or more path pairs");
9067cc0636SGreg Clayton     }
9167cc0636SGreg Clayton     break;
9267cc0636SGreg Clayton 
9367cc0636SGreg Clayton   case eVarSetOperationAssign:
94b9c1b51eSKate Stone     if (argc < 2 || (argc & 1)) {
9567cc0636SGreg Clayton       error.SetErrorString("assign operation takes one or more path pairs");
9667cc0636SGreg Clayton       break;
9767cc0636SGreg Clayton     }
9867cc0636SGreg Clayton     m_path_mappings.Clear(m_notify_changes);
9967cc0636SGreg Clayton     // Fall through to append case
10062e0681aSJason Molenda     LLVM_FALLTHROUGH;
10167cc0636SGreg Clayton   case eVarSetOperationAppend:
102b9c1b51eSKate Stone     if (argc < 2 || (argc & 1)) {
10367cc0636SGreg Clayton       error.SetErrorString("append operation takes one or more path pairs");
10467cc0636SGreg Clayton       break;
105b9c1b51eSKate Stone     } else {
1066a311641SGreg Clayton       bool changed = false;
107b9c1b51eSKate Stone       for (size_t i = 0; i < argc; i += 2) {
1086a311641SGreg Clayton         const char *orginal_path = args.GetArgumentAtIndex(i);
1096a311641SGreg Clayton         const char *replace_path = args.GetArgumentAtIndex(i + 1);
110b9c1b51eSKate Stone         if (VerifyPathExists(replace_path)) {
1116a311641SGreg Clayton           ConstString a(orginal_path);
1126a311641SGreg Clayton           ConstString b(replace_path);
11367cc0636SGreg Clayton           m_path_mappings.Append(a, b, m_notify_changes);
11467cc0636SGreg Clayton           m_value_was_set = true;
1156a311641SGreg Clayton           changed = true;
116b9c1b51eSKate Stone         } else {
117b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
118b9c1b51eSKate Stone               "the replacement path doesn't exist: \"%s\"", replace_path);
1196a311641SGreg Clayton           break;
1206a311641SGreg Clayton         }
1216a311641SGreg Clayton       }
1226a311641SGreg Clayton       if (changed)
123332e8b1cSGreg Clayton         NotifyValueChanged();
12467cc0636SGreg Clayton     }
12567cc0636SGreg Clayton     break;
12667cc0636SGreg Clayton 
12767cc0636SGreg Clayton   case eVarSetOperationInsertBefore:
12867cc0636SGreg Clayton   case eVarSetOperationInsertAfter:
129b9c1b51eSKate Stone     // Must be at least one index + 1 pair of paths, and the pair count must be
130b9c1b51eSKate Stone     // even
131b9c1b51eSKate Stone     if (argc >= 3 && (((argc - 1) & 1) == 0)) {
132b9c1b51eSKate Stone       uint32_t idx =
133b9c1b51eSKate Stone           StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
13467cc0636SGreg Clayton       const uint32_t count = m_path_mappings.GetSize();
135b9c1b51eSKate Stone       if (idx > count) {
136b9c1b51eSKate Stone         error.SetErrorStringWithFormat(
137b9c1b51eSKate Stone             "invalid file list index %u, index must be 0 through %u", idx,
138b9c1b51eSKate Stone             count);
139b9c1b51eSKate Stone       } else {
1406a311641SGreg Clayton         bool changed = false;
14167cc0636SGreg Clayton         if (op == eVarSetOperationInsertAfter)
14267cc0636SGreg Clayton           ++idx;
143b9c1b51eSKate Stone         for (size_t i = 1; i < argc; i += 2, ++idx) {
1446a311641SGreg Clayton           const char *orginal_path = args.GetArgumentAtIndex(i);
1456a311641SGreg Clayton           const char *replace_path = args.GetArgumentAtIndex(i + 1);
146b9c1b51eSKate Stone           if (VerifyPathExists(replace_path)) {
1476a311641SGreg Clayton             ConstString a(orginal_path);
1486a311641SGreg Clayton             ConstString b(replace_path);
14967cc0636SGreg Clayton             m_path_mappings.Insert(a, b, idx, m_notify_changes);
1506a311641SGreg Clayton             changed = true;
151b9c1b51eSKate Stone           } else {
152b9c1b51eSKate Stone             error.SetErrorStringWithFormat(
153b9c1b51eSKate Stone                 "the replacement path doesn't exist: \"%s\"", replace_path);
1546a311641SGreg Clayton             break;
1556a311641SGreg Clayton           }
1566a311641SGreg Clayton         }
1576a311641SGreg Clayton         if (changed)
158332e8b1cSGreg Clayton           NotifyValueChanged();
15967cc0636SGreg Clayton       }
160b9c1b51eSKate Stone     } else {
161b9c1b51eSKate Stone       error.SetErrorString("insert operation takes an array index followed by "
162b9c1b51eSKate Stone                            "one or more path pairs");
16367cc0636SGreg Clayton     }
16467cc0636SGreg Clayton     break;
16567cc0636SGreg Clayton 
16667cc0636SGreg Clayton   case eVarSetOperationRemove:
167b9c1b51eSKate Stone     if (argc > 0) {
16867cc0636SGreg Clayton       std::vector<int> remove_indexes;
16967cc0636SGreg Clayton       bool all_indexes_valid = true;
17067cc0636SGreg Clayton       size_t i;
171b9c1b51eSKate Stone       for (i = 0; all_indexes_valid && i < argc; ++i) {
172b9c1b51eSKate Stone         const int idx =
173b9c1b51eSKate Stone             StringConvert::ToSInt32(args.GetArgumentAtIndex(i), INT32_MAX);
17467cc0636SGreg Clayton         if (idx == INT32_MAX)
17567cc0636SGreg Clayton           all_indexes_valid = false;
17667cc0636SGreg Clayton         else
17767cc0636SGreg Clayton           remove_indexes.push_back(idx);
17867cc0636SGreg Clayton       }
17967cc0636SGreg Clayton 
180b9c1b51eSKate Stone       if (all_indexes_valid) {
18167cc0636SGreg Clayton         size_t num_remove_indexes = remove_indexes.size();
182b9c1b51eSKate Stone         if (num_remove_indexes) {
18367cc0636SGreg Clayton           // Sort and then erase in reverse so indexes are always valid
18467cc0636SGreg Clayton           std::sort(remove_indexes.begin(), remove_indexes.end());
185b9c1b51eSKate Stone           for (size_t j = num_remove_indexes - 1; j < num_remove_indexes; ++j) {
186ccd41e55SJason Molenda             m_path_mappings.Remove(j, m_notify_changes);
18767cc0636SGreg Clayton           }
18867cc0636SGreg Clayton         }
189332e8b1cSGreg Clayton         NotifyValueChanged();
190b9c1b51eSKate Stone       } else {
191b9c1b51eSKate Stone         error.SetErrorStringWithFormat(
192b9c1b51eSKate Stone             "invalid array index '%s', aborting remove operation",
193b9c1b51eSKate Stone             args.GetArgumentAtIndex(i));
19467cc0636SGreg Clayton       }
195b9c1b51eSKate Stone     } else {
19667cc0636SGreg Clayton       error.SetErrorString("remove operation takes one or more array index");
19767cc0636SGreg Clayton     }
19867cc0636SGreg Clayton     break;
19967cc0636SGreg Clayton 
20067cc0636SGreg Clayton   case eVarSetOperationInvalid:
201c95f7e2aSPavel Labath     error = OptionValue::SetValueFromString(value, op);
20267cc0636SGreg Clayton     break;
20367cc0636SGreg Clayton   }
20467cc0636SGreg Clayton   return error;
20567cc0636SGreg Clayton }
20667cc0636SGreg Clayton 
207b9c1b51eSKate Stone lldb::OptionValueSP OptionValuePathMappings::DeepCopy() const {
20867cc0636SGreg Clayton   return OptionValueSP(new OptionValuePathMappings(*this));
20967cc0636SGreg Clayton }
210