xref: /freebsd/contrib/llvm-project/lldb/source/Interpreter/OptionValueFileSpecList.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
DumpValue(const ExecutionContext * exe_ctx,Stream & strm,uint32_t dump_mask)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 llvm::json::Value
ToJSON(const ExecutionContext * exe_ctx) const45 OptionValueFileSpecList::ToJSON(const ExecutionContext *exe_ctx) const {
46   std::lock_guard<std::recursive_mutex> lock(m_mutex);
47   llvm::json::Array array;
48   for (const auto &file_spec : m_current_value)
49     array.emplace_back(file_spec.ToJSON());
50   return array;
51 }
52 
SetValueFromString(llvm::StringRef value,VarSetOperationType op)53 Status OptionValueFileSpecList::SetValueFromString(llvm::StringRef value,
54                                                    VarSetOperationType op) {
55   std::lock_guard<std::recursive_mutex> lock(m_mutex);
56   Status error;
57   Args args(value.str());
58   const size_t argc = args.GetArgumentCount();
59 
60   switch (op) {
61   case eVarSetOperationClear:
62     Clear();
63     NotifyValueChanged();
64     break;
65 
66   case eVarSetOperationReplace:
67     if (argc > 1) {
68       uint32_t idx;
69       const uint32_t count = m_current_value.GetSize();
70       if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {
71         error = Status::FromErrorStringWithFormat(
72             "invalid file list index %s, index must be 0 through %u",
73             args.GetArgumentAtIndex(0), count);
74       } else {
75         for (size_t i = 1; i < argc; ++i, ++idx) {
76           FileSpec file(args.GetArgumentAtIndex(i));
77           if (idx < count)
78             m_current_value.Replace(idx, file);
79           else
80             m_current_value.Append(file);
81         }
82         NotifyValueChanged();
83       }
84     } else {
85       error = Status::FromErrorString(
86           "replace operation takes an array index followed by "
87           "one or more values");
88     }
89     break;
90 
91   case eVarSetOperationAssign:
92     m_current_value.Clear();
93     // Fall through to append case
94     [[fallthrough]];
95   case eVarSetOperationAppend:
96     if (argc > 0) {
97       m_value_was_set = true;
98       for (size_t i = 0; i < argc; ++i) {
99         FileSpec file(args.GetArgumentAtIndex(i));
100         m_current_value.Append(file);
101       }
102       NotifyValueChanged();
103     } else {
104       error = Status::FromErrorString(
105           "assign operation takes at least one file path argument");
106     }
107     break;
108 
109   case eVarSetOperationInsertBefore:
110   case eVarSetOperationInsertAfter:
111     if (argc > 1) {
112       uint32_t idx;
113       const uint32_t count = m_current_value.GetSize();
114       if (!llvm::to_integer(args.GetArgumentAtIndex(0), idx) || idx > count) {
115         error = Status::FromErrorStringWithFormat(
116             "invalid insert file list index %s, index must be 0 through %u",
117             args.GetArgumentAtIndex(0), count);
118       } else {
119         if (op == eVarSetOperationInsertAfter)
120           ++idx;
121         for (size_t i = 1; i < argc; ++i, ++idx) {
122           FileSpec file(args.GetArgumentAtIndex(i));
123           m_current_value.Insert(idx, file);
124         }
125         NotifyValueChanged();
126       }
127     } else {
128       error = Status::FromErrorString(
129           "insert operation takes an array index followed by "
130           "one or more values");
131     }
132     break;
133 
134   case eVarSetOperationRemove:
135     if (argc > 0) {
136       std::vector<int> remove_indexes;
137       bool all_indexes_valid = true;
138       size_t i;
139       for (i = 0; all_indexes_valid && i < argc; ++i) {
140         int idx;
141         if (!llvm::to_integer(args.GetArgumentAtIndex(i), idx))
142           all_indexes_valid = false;
143         else
144           remove_indexes.push_back(idx);
145       }
146 
147       if (all_indexes_valid) {
148         size_t num_remove_indexes = remove_indexes.size();
149         if (num_remove_indexes) {
150           // Sort and then erase in reverse so indexes are always valid
151           llvm::sort(remove_indexes);
152           for (size_t j = num_remove_indexes - 1; j < num_remove_indexes; ++j) {
153             m_current_value.Remove(j);
154           }
155         }
156         NotifyValueChanged();
157       } else {
158         error = Status::FromErrorStringWithFormat(
159             "invalid array index '%s', aborting remove operation",
160             args.GetArgumentAtIndex(i));
161       }
162     } else {
163       error = Status::FromErrorString(
164           "remove operation takes one or more array index");
165     }
166     break;
167 
168   case eVarSetOperationInvalid:
169     error = OptionValue::SetValueFromString(value, op);
170     break;
171   }
172   return error;
173 }
174 
Clone() const175 OptionValueSP OptionValueFileSpecList::Clone() const {
176   std::lock_guard<std::recursive_mutex> lock(m_mutex);
177   return Cloneable::Clone();
178 }
179