OptionValuePathMappings.cpp revision 341825
1//===-- OptionValuePathMappings.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/OptionValuePathMappings.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/Host/StringConvert.h"
17#include "lldb/Utility/Args.h"
18#include "lldb/Utility/FileSpec.h"
19#include "lldb/Utility/Stream.h"
20
21using namespace lldb;
22using namespace lldb_private;
23namespace {
24static bool VerifyPathExists(const char *path) {
25  if (path && path[0])
26    return FileSpec(path, false).Exists();
27  else
28    return false;
29}
30}
31
32void OptionValuePathMappings::DumpValue(const ExecutionContext *exe_ctx,
33                                        Stream &strm, uint32_t dump_mask) {
34  if (dump_mask & eDumpOptionType)
35    strm.Printf("(%s)", GetTypeAsCString());
36  if (dump_mask & eDumpOptionValue) {
37    if (dump_mask & eDumpOptionType)
38      strm.Printf(" =%s", (m_path_mappings.GetSize() > 0) ? "\n" : "");
39    m_path_mappings.Dump(&strm);
40  }
41}
42
43Status OptionValuePathMappings::SetValueFromString(llvm::StringRef value,
44                                                   VarSetOperationType op) {
45  Status error;
46  Args args(value.str());
47  const size_t argc = args.GetArgumentCount();
48
49  switch (op) {
50  case eVarSetOperationClear:
51    Clear();
52    NotifyValueChanged();
53    break;
54
55  case eVarSetOperationReplace:
56    // Must be at least one index + 1 pair of paths, and the pair count must be
57    // even
58    if (argc >= 3 && (((argc - 1) & 1) == 0)) {
59      uint32_t idx =
60          StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
61      const uint32_t count = m_path_mappings.GetSize();
62      if (idx > count) {
63        error.SetErrorStringWithFormat(
64            "invalid file list index %u, index must be 0 through %u", idx,
65            count);
66      } else {
67        bool changed = false;
68        for (size_t i = 1; i < argc; i += 2, ++idx) {
69          const char *orginal_path = args.GetArgumentAtIndex(i);
70          const char *replace_path = args.GetArgumentAtIndex(i + 1);
71          if (VerifyPathExists(replace_path)) {
72            ConstString a(orginal_path);
73            ConstString b(replace_path);
74            if (!m_path_mappings.Replace(a, b, idx, m_notify_changes))
75              m_path_mappings.Append(a, b, m_notify_changes);
76            changed = true;
77          } else {
78            error.SetErrorStringWithFormat(
79                "the replacement path doesn't exist: \"%s\"", replace_path);
80            break;
81          }
82        }
83        if (changed)
84          NotifyValueChanged();
85      }
86    } else {
87      error.SetErrorString("replace operation takes an array index followed by "
88                           "one or more path pairs");
89    }
90    break;
91
92  case eVarSetOperationAssign:
93    if (argc < 2 || (argc & 1)) {
94      error.SetErrorString("assign operation takes one or more path pairs");
95      break;
96    }
97    m_path_mappings.Clear(m_notify_changes);
98    // Fall through to append case
99    LLVM_FALLTHROUGH;
100  case eVarSetOperationAppend:
101    if (argc < 2 || (argc & 1)) {
102      error.SetErrorString("append operation takes one or more path pairs");
103      break;
104    } else {
105      bool changed = false;
106      for (size_t i = 0; i < argc; i += 2) {
107        const char *orginal_path = args.GetArgumentAtIndex(i);
108        const char *replace_path = args.GetArgumentAtIndex(i + 1);
109        if (VerifyPathExists(replace_path)) {
110          ConstString a(orginal_path);
111          ConstString b(replace_path);
112          m_path_mappings.Append(a, b, m_notify_changes);
113          m_value_was_set = true;
114          changed = true;
115        } else {
116          error.SetErrorStringWithFormat(
117              "the replacement path doesn't exist: \"%s\"", replace_path);
118          break;
119        }
120      }
121      if (changed)
122        NotifyValueChanged();
123    }
124    break;
125
126  case eVarSetOperationInsertBefore:
127  case eVarSetOperationInsertAfter:
128    // Must be at least one index + 1 pair of paths, and the pair count must be
129    // even
130    if (argc >= 3 && (((argc - 1) & 1) == 0)) {
131      uint32_t idx =
132          StringConvert::ToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
133      const uint32_t count = m_path_mappings.GetSize();
134      if (idx > count) {
135        error.SetErrorStringWithFormat(
136            "invalid file list index %u, index must be 0 through %u", idx,
137            count);
138      } else {
139        bool changed = false;
140        if (op == eVarSetOperationInsertAfter)
141          ++idx;
142        for (size_t i = 1; i < argc; i += 2, ++idx) {
143          const char *orginal_path = args.GetArgumentAtIndex(i);
144          const char *replace_path = args.GetArgumentAtIndex(i + 1);
145          if (VerifyPathExists(replace_path)) {
146            ConstString a(orginal_path);
147            ConstString b(replace_path);
148            m_path_mappings.Insert(a, b, idx, m_notify_changes);
149            changed = true;
150          } else {
151            error.SetErrorStringWithFormat(
152                "the replacement path doesn't exist: \"%s\"", replace_path);
153            break;
154          }
155        }
156        if (changed)
157          NotifyValueChanged();
158      }
159    } else {
160      error.SetErrorString("insert operation takes an array index followed by "
161                           "one or more path pairs");
162    }
163    break;
164
165  case eVarSetOperationRemove:
166    if (argc > 0) {
167      std::vector<int> remove_indexes;
168      bool all_indexes_valid = true;
169      size_t i;
170      for (i = 0; all_indexes_valid && i < argc; ++i) {
171        const int idx =
172            StringConvert::ToSInt32(args.GetArgumentAtIndex(i), INT32_MAX);
173        if (idx == INT32_MAX)
174          all_indexes_valid = false;
175        else
176          remove_indexes.push_back(idx);
177      }
178
179      if (all_indexes_valid) {
180        size_t num_remove_indexes = remove_indexes.size();
181        if (num_remove_indexes) {
182          // Sort and then erase in reverse so indexes are always valid
183          std::sort(remove_indexes.begin(), remove_indexes.end());
184          for (size_t j = num_remove_indexes - 1; j < num_remove_indexes; ++j) {
185            m_path_mappings.Remove(j, m_notify_changes);
186          }
187        }
188        NotifyValueChanged();
189      } else {
190        error.SetErrorStringWithFormat(
191            "invalid array index '%s', aborting remove operation",
192            args.GetArgumentAtIndex(i));
193      }
194    } else {
195      error.SetErrorString("remove operation takes one or more array index");
196    }
197    break;
198
199  case eVarSetOperationInvalid:
200    error = OptionValue::SetValueFromString(value, op);
201    break;
202  }
203  return error;
204}
205
206lldb::OptionValueSP OptionValuePathMappings::DeepCopy() const {
207  return OptionValueSP(new OptionValuePathMappings(*this));
208}
209