xref: /llvm-project/lldb/source/Interpreter/OptionValueFileSpecList.cpp (revision 0642cd768b80665585c8500bed2933a3b99123dc)
1 //===-- OptionValueFileSpecList.cpp ---------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/Interpreter/OptionValueFileSpecList.h"
10 
11 #include "lldb/Utility/Args.h"
12 #include "lldb/Utility/Stream.h"
13 
14 using namespace lldb;
15 using namespace lldb_private;
16 
17 void OptionValueFileSpecList::DumpValue(const ExecutionContext *exe_ctx,
18                                         Stream &strm, uint32_t dump_mask) {
19   std::lock_guard<std::recursive_mutex> lock(m_mutex);
20   if (dump_mask & eDumpOptionType)
21     strm.Printf("(%s)", GetTypeAsCString());
22   if (dump_mask & eDumpOptionValue) {
23     const bool one_line = dump_mask & eDumpOptionCommand;
24     const uint32_t size = m_current_value.GetSize();
25     if (dump_mask & eDumpOptionType)
26       strm.Printf(" =%s",
27                   (m_current_value.GetSize() > 0 && !one_line) ? "\n" : "");
28     if (!one_line)
29       strm.IndentMore();
30     for (uint32_t i = 0; i < size; ++i) {
31       if (!one_line) {
32         strm.Indent();
33         strm.Printf("[%u]: ", i);
34       }
35       m_current_value.GetFileSpecAtIndex(i).Dump(strm.AsRawOstream());
36       if (one_line)
37         strm << ' ';
38     }
39     if (!one_line)
40       strm.IndentLess();
41   }
42 }
43 
44 Status OptionValueFileSpecList::SetValueFromString(llvm::StringRef value,
45                                                    VarSetOperationType op) {
46   std::lock_guard<std::recursive_mutex> lock(m_mutex);
47   Status error;
48   Args args(value.str());
49   const size_t argc = args.GetArgumentCount();
50 
51   switch (op) {
52   case eVarSetOperationClear:
53     Clear();
54     NotifyValueChanged();
55     break;
56 
57   case eVarSetOperationReplace:
58     if (argc > 1) {
59       uint32_t idx;
60       const uint32_t count = m_current_value.GetSize();
61       if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {
62         error = Status::FromErrorStringWithFormat(
63             "invalid file list index %s, index must be 0 through %u",
64             args.GetArgumentAtIndex(0), count);
65       } else {
66         for (size_t i = 1; i < argc; ++i, ++idx) {
67           FileSpec file(args.GetArgumentAtIndex(i));
68           if (idx < count)
69             m_current_value.Replace(idx, file);
70           else
71             m_current_value.Append(file);
72         }
73         NotifyValueChanged();
74       }
75     } else {
76       error = Status::FromErrorString(
77           "replace operation takes an array index followed by "
78           "one or more values");
79     }
80     break;
81 
82   case eVarSetOperationAssign:
83     m_current_value.Clear();
84     // Fall through to append case
85     [[fallthrough]];
86   case eVarSetOperationAppend:
87     if (argc > 0) {
88       m_value_was_set = true;
89       for (size_t i = 0; i < argc; ++i) {
90         FileSpec file(args.GetArgumentAtIndex(i));
91         m_current_value.Append(file);
92       }
93       NotifyValueChanged();
94     } else {
95       error = Status::FromErrorString(
96           "assign operation takes at least one file path argument");
97     }
98     break;
99 
100   case eVarSetOperationInsertBefore:
101   case eVarSetOperationInsertAfter:
102     if (argc > 1) {
103       uint32_t idx;
104       const uint32_t count = m_current_value.GetSize();
105       if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {
106         error = Status::FromErrorStringWithFormat(
107             "invalid insert file list index %s, index must be 0 through %u",
108             args.GetArgumentAtIndex(0), count);
109       } else {
110         if (op == eVarSetOperationInsertAfter)
111           ++idx;
112         for (size_t i = 1; i < argc; ++i, ++idx) {
113           FileSpec file(args.GetArgumentAtIndex(i));
114           m_current_value.Insert(idx, file);
115         }
116         NotifyValueChanged();
117       }
118     } else {
119       error = Status::FromErrorString(
120           "insert operation takes an array index followed by "
121           "one or more values");
122     }
123     break;
124 
125   case eVarSetOperationRemove:
126     if (argc > 0) {
127       std::vector<int> remove_indexes;
128       bool all_indexes_valid = true;
129       size_t i;
130       for (i = 0; all_indexes_valid && i < argc; ++i) {
131         int idx;
132         if (!llvm::to_integer(args.GetArgumentAtIndex(i), idx))
133           all_indexes_valid = false;
134         else
135           remove_indexes.push_back(idx);
136       }
137 
138       if (all_indexes_valid) {
139         size_t num_remove_indexes = remove_indexes.size();
140         if (num_remove_indexes) {
141           // Sort and then erase in reverse so indexes are always valid
142           llvm::sort(remove_indexes);
143           for (size_t j = num_remove_indexes - 1; j < num_remove_indexes; ++j) {
144             m_current_value.Remove(j);
145           }
146         }
147         NotifyValueChanged();
148       } else {
149         error = Status::FromErrorStringWithFormat(
150             "invalid array index '%s', aborting remove operation",
151             args.GetArgumentAtIndex(i));
152       }
153     } else {
154       error = Status::FromErrorString(
155           "remove operation takes one or more array index");
156     }
157     break;
158 
159   case eVarSetOperationInvalid:
160     error = OptionValue::SetValueFromString(value, op);
161     break;
162   }
163   return error;
164 }
165 
166 OptionValueSP OptionValueFileSpecList::Clone() const {
167   std::lock_guard<std::recursive_mutex> lock(m_mutex);
168   return Cloneable::Clone();
169 }
170