File: | tools/lldb/source/Utility/Args.cpp |
Warning: | line 723, column 5 Value stored to 'found_suffix' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- Args.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/Utility/Args.h" |
11 | #include "lldb/Utility/ConstString.h" |
12 | #include "lldb/Utility/FileSpec.h" |
13 | #include "lldb/Utility/Stream.h" |
14 | #include "lldb/Utility/StringList.h" |
15 | #include "llvm/ADT/StringSwitch.h" |
16 | |
17 | using namespace lldb; |
18 | using namespace lldb_private; |
19 | |
20 | // A helper function for argument parsing. |
21 | // Parses the initial part of the first argument using normal double quote |
22 | // rules: backslash escapes the double quote and itself. The parsed string is |
23 | // appended to the second argument. The function returns the unparsed portion |
24 | // of the string, starting at the closing quote. |
25 | static llvm::StringRef ParseDoubleQuotes(llvm::StringRef quoted, |
26 | std::string &result) { |
27 | // Inside double quotes, '\' and '"' are special. |
28 | static const char *k_escapable_characters = "\"\\"; |
29 | while (true) { |
30 | // Skip over over regular characters and append them. |
31 | size_t regular = quoted.find_first_of(k_escapable_characters); |
32 | result += quoted.substr(0, regular); |
33 | quoted = quoted.substr(regular); |
34 | |
35 | // If we have reached the end of string or the closing quote, we're done. |
36 | if (quoted.empty() || quoted.front() == '"') |
37 | break; |
38 | |
39 | // We have found a backslash. |
40 | quoted = quoted.drop_front(); |
41 | |
42 | if (quoted.empty()) { |
43 | // A lone backslash at the end of string, let's just append it. |
44 | result += '\\'; |
45 | break; |
46 | } |
47 | |
48 | // If the character after the backslash is not a whitelisted escapable |
49 | // character, we leave the character sequence untouched. |
50 | if (strchr(k_escapable_characters, quoted.front()) == nullptr) |
51 | result += '\\'; |
52 | |
53 | result += quoted.front(); |
54 | quoted = quoted.drop_front(); |
55 | } |
56 | |
57 | return quoted; |
58 | } |
59 | |
60 | static size_t ArgvToArgc(const char **argv) { |
61 | if (!argv) |
62 | return 0; |
63 | size_t count = 0; |
64 | while (*argv++) |
65 | ++count; |
66 | return count; |
67 | } |
68 | |
69 | // Trims all whitespace that can separate command line arguments from the left |
70 | // side of the string. |
71 | static llvm::StringRef ltrimForArgs(llvm::StringRef str) { |
72 | static const char *k_space_separators = " \t"; |
73 | return str.ltrim(k_space_separators); |
74 | } |
75 | |
76 | // A helper function for SetCommandString. Parses a single argument from the |
77 | // command string, processing quotes and backslashes in a shell-like manner. |
78 | // The function returns a tuple consisting of the parsed argument, the quote |
79 | // char used, and the unparsed portion of the string starting at the first |
80 | // unqouted, unescaped whitespace character. |
81 | static std::tuple<std::string, char, llvm::StringRef> |
82 | ParseSingleArgument(llvm::StringRef command) { |
83 | // Argument can be split into multiple discontiguous pieces, for example: |
84 | // "Hello ""World" |
85 | // this would result in a single argument "Hello World" (without the quotes) |
86 | // since the quotes would be removed and there is not space between the |
87 | // strings. |
88 | std::string arg; |
89 | |
90 | // Since we can have multiple quotes that form a single command in a command |
91 | // like: "Hello "world'!' (which will make a single argument "Hello world!") |
92 | // we remember the first quote character we encounter and use that for the |
93 | // quote character. |
94 | char first_quote_char = '\0'; |
95 | |
96 | bool arg_complete = false; |
97 | do { |
98 | // Skip over over regular characters and append them. |
99 | size_t regular = command.find_first_of(" \t\"'`\\"); |
100 | arg += command.substr(0, regular); |
101 | command = command.substr(regular); |
102 | |
103 | if (command.empty()) |
104 | break; |
105 | |
106 | char special = command.front(); |
107 | command = command.drop_front(); |
108 | switch (special) { |
109 | case '\\': |
110 | if (command.empty()) { |
111 | arg += '\\'; |
112 | break; |
113 | } |
114 | |
115 | // If the character after the backslash is not a whitelisted escapable |
116 | // character, we leave the character sequence untouched. |
117 | if (strchr(" \t\\'\"`", command.front()) == nullptr) |
118 | arg += '\\'; |
119 | |
120 | arg += command.front(); |
121 | command = command.drop_front(); |
122 | |
123 | break; |
124 | |
125 | case ' ': |
126 | case '\t': |
127 | // We are not inside any quotes, we just found a space after an argument. |
128 | // We are done. |
129 | arg_complete = true; |
130 | break; |
131 | |
132 | case '"': |
133 | case '\'': |
134 | case '`': |
135 | // We found the start of a quote scope. |
136 | if (first_quote_char == '\0') |
137 | first_quote_char = special; |
138 | |
139 | if (special == '"') |
140 | command = ParseDoubleQuotes(command, arg); |
141 | else { |
142 | // For single quotes, we simply skip ahead to the matching quote |
143 | // character (or the end of the string). |
144 | size_t quoted = command.find(special); |
145 | arg += command.substr(0, quoted); |
146 | command = command.substr(quoted); |
147 | } |
148 | |
149 | // If we found a closing quote, skip it. |
150 | if (!command.empty()) |
151 | command = command.drop_front(); |
152 | |
153 | break; |
154 | } |
155 | } while (!arg_complete); |
156 | |
157 | return std::make_tuple(arg, first_quote_char, command); |
158 | } |
159 | |
160 | Args::ArgEntry::ArgEntry(llvm::StringRef str, char quote) : quote(quote) { |
161 | size_t size = str.size(); |
162 | ptr.reset(new char[size + 1]); |
163 | |
164 | ::memcpy(data(), str.data() ? str.data() : "", size); |
165 | ptr[size] = 0; |
166 | ref = llvm::StringRef(c_str(), size); |
167 | } |
168 | |
169 | //---------------------------------------------------------------------- |
170 | // Args constructor |
171 | //---------------------------------------------------------------------- |
172 | Args::Args(llvm::StringRef command) { SetCommandString(command); } |
173 | |
174 | Args::Args(const Args &rhs) { *this = rhs; } |
175 | |
176 | Args::Args(const StringList &list) : Args() { |
177 | for (size_t i = 0; i < list.GetSize(); ++i) |
178 | AppendArgument(list[i]); |
179 | } |
180 | |
181 | Args &Args::operator=(const Args &rhs) { |
182 | Clear(); |
183 | |
184 | m_argv.clear(); |
185 | m_entries.clear(); |
186 | for (auto &entry : rhs.m_entries) { |
187 | m_entries.emplace_back(entry.ref, entry.quote); |
188 | m_argv.push_back(m_entries.back().data()); |
189 | } |
190 | m_argv.push_back(nullptr); |
191 | return *this; |
192 | } |
193 | |
194 | //---------------------------------------------------------------------- |
195 | // Destructor |
196 | //---------------------------------------------------------------------- |
197 | Args::~Args() {} |
198 | |
199 | void Args::Dump(Stream &s, const char *label_name) const { |
200 | if (!label_name) |
201 | return; |
202 | |
203 | int i = 0; |
204 | for (auto &entry : m_entries) { |
205 | s.Indent(); |
206 | s.Format("{0}[{1}]=\"{2}\"\n", label_name, i++, entry.ref); |
207 | } |
208 | s.Format("{0}[{1}]=NULL\n", label_name, i); |
209 | s.EOL(); |
210 | } |
211 | |
212 | bool Args::GetCommandString(std::string &command) const { |
213 | command.clear(); |
214 | |
215 | for (size_t i = 0; i < m_entries.size(); ++i) { |
216 | if (i > 0) |
217 | command += ' '; |
218 | command += m_entries[i].ref; |
219 | } |
220 | |
221 | return !m_entries.empty(); |
222 | } |
223 | |
224 | bool Args::GetQuotedCommandString(std::string &command) const { |
225 | command.clear(); |
226 | |
227 | for (size_t i = 0; i < m_entries.size(); ++i) { |
228 | if (i > 0) |
229 | command += ' '; |
230 | |
231 | if (m_entries[i].quote) { |
232 | command += m_entries[i].quote; |
233 | command += m_entries[i].ref; |
234 | command += m_entries[i].quote; |
235 | } else { |
236 | command += m_entries[i].ref; |
237 | } |
238 | } |
239 | |
240 | return !m_entries.empty(); |
241 | } |
242 | |
243 | void Args::SetCommandString(llvm::StringRef command) { |
244 | Clear(); |
245 | m_argv.clear(); |
246 | |
247 | command = ltrimForArgs(command); |
248 | std::string arg; |
249 | char quote; |
250 | while (!command.empty()) { |
251 | std::tie(arg, quote, command) = ParseSingleArgument(command); |
252 | m_entries.emplace_back(arg, quote); |
253 | m_argv.push_back(m_entries.back().data()); |
254 | command = ltrimForArgs(command); |
255 | } |
256 | m_argv.push_back(nullptr); |
257 | } |
258 | |
259 | size_t Args::GetArgumentCount() const { return m_entries.size(); } |
260 | |
261 | const char *Args::GetArgumentAtIndex(size_t idx) const { |
262 | if (idx < m_argv.size()) |
263 | return m_argv[idx]; |
264 | return nullptr; |
265 | } |
266 | |
267 | char Args::GetArgumentQuoteCharAtIndex(size_t idx) const { |
268 | if (idx < m_entries.size()) |
269 | return m_entries[idx].quote; |
270 | return '\0'; |
271 | } |
272 | |
273 | char **Args::GetArgumentVector() { |
274 | assert(!m_argv.empty())((!m_argv.empty()) ? static_cast<void> (0) : __assert_fail ("!m_argv.empty()", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Utility/Args.cpp" , 274, __PRETTY_FUNCTION__)); |
275 | // TODO: functions like execve and posix_spawnp exhibit undefined behavior |
276 | // when argv or envp is null. So the code below is actually wrong. However, |
277 | // other code in LLDB depends on it being null. The code has been acting |
278 | // this way for some time, so it makes sense to leave it this way until |
279 | // someone has the time to come along and fix it. |
280 | return (m_argv.size() > 1) ? m_argv.data() : nullptr; |
281 | } |
282 | |
283 | const char **Args::GetConstArgumentVector() const { |
284 | assert(!m_argv.empty())((!m_argv.empty()) ? static_cast<void> (0) : __assert_fail ("!m_argv.empty()", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Utility/Args.cpp" , 284, __PRETTY_FUNCTION__)); |
285 | return (m_argv.size() > 1) ? const_cast<const char **>(m_argv.data()) |
286 | : nullptr; |
287 | } |
288 | |
289 | void Args::Shift() { |
290 | // Don't pop the last NULL terminator from the argv array |
291 | if (m_entries.empty()) |
292 | return; |
293 | m_argv.erase(m_argv.begin()); |
294 | m_entries.erase(m_entries.begin()); |
295 | } |
296 | |
297 | void Args::Unshift(llvm::StringRef arg_str, char quote_char) { |
298 | InsertArgumentAtIndex(0, arg_str, quote_char); |
299 | } |
300 | |
301 | void Args::AppendArguments(const Args &rhs) { |
302 | assert(m_argv.size() == m_entries.size() + 1)((m_argv.size() == m_entries.size() + 1) ? static_cast<void > (0) : __assert_fail ("m_argv.size() == m_entries.size() + 1" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Utility/Args.cpp" , 302, __PRETTY_FUNCTION__)); |
303 | assert(m_argv.back() == nullptr)((m_argv.back() == nullptr) ? static_cast<void> (0) : __assert_fail ("m_argv.back() == nullptr", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Utility/Args.cpp" , 303, __PRETTY_FUNCTION__)); |
304 | m_argv.pop_back(); |
305 | for (auto &entry : rhs.m_entries) { |
306 | m_entries.emplace_back(entry.ref, entry.quote); |
307 | m_argv.push_back(m_entries.back().data()); |
308 | } |
309 | m_argv.push_back(nullptr); |
310 | } |
311 | |
312 | void Args::AppendArguments(const char **argv) { |
313 | size_t argc = ArgvToArgc(argv); |
314 | |
315 | assert(m_argv.size() == m_entries.size() + 1)((m_argv.size() == m_entries.size() + 1) ? static_cast<void > (0) : __assert_fail ("m_argv.size() == m_entries.size() + 1" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Utility/Args.cpp" , 315, __PRETTY_FUNCTION__)); |
316 | assert(m_argv.back() == nullptr)((m_argv.back() == nullptr) ? static_cast<void> (0) : __assert_fail ("m_argv.back() == nullptr", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Utility/Args.cpp" , 316, __PRETTY_FUNCTION__)); |
317 | m_argv.pop_back(); |
318 | for (auto arg : llvm::makeArrayRef(argv, argc)) { |
319 | m_entries.emplace_back(arg, '\0'); |
320 | m_argv.push_back(m_entries.back().data()); |
321 | } |
322 | |
323 | m_argv.push_back(nullptr); |
324 | } |
325 | |
326 | void Args::AppendArgument(llvm::StringRef arg_str, char quote_char) { |
327 | InsertArgumentAtIndex(GetArgumentCount(), arg_str, quote_char); |
328 | } |
329 | |
330 | void Args::InsertArgumentAtIndex(size_t idx, llvm::StringRef arg_str, |
331 | char quote_char) { |
332 | assert(m_argv.size() == m_entries.size() + 1)((m_argv.size() == m_entries.size() + 1) ? static_cast<void > (0) : __assert_fail ("m_argv.size() == m_entries.size() + 1" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Utility/Args.cpp" , 332, __PRETTY_FUNCTION__)); |
333 | assert(m_argv.back() == nullptr)((m_argv.back() == nullptr) ? static_cast<void> (0) : __assert_fail ("m_argv.back() == nullptr", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Utility/Args.cpp" , 333, __PRETTY_FUNCTION__)); |
334 | |
335 | if (idx > m_entries.size()) |
336 | return; |
337 | m_entries.emplace(m_entries.begin() + idx, arg_str, quote_char); |
338 | m_argv.insert(m_argv.begin() + idx, m_entries[idx].data()); |
339 | } |
340 | |
341 | void Args::ReplaceArgumentAtIndex(size_t idx, llvm::StringRef arg_str, |
342 | char quote_char) { |
343 | assert(m_argv.size() == m_entries.size() + 1)((m_argv.size() == m_entries.size() + 1) ? static_cast<void > (0) : __assert_fail ("m_argv.size() == m_entries.size() + 1" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Utility/Args.cpp" , 343, __PRETTY_FUNCTION__)); |
344 | assert(m_argv.back() == nullptr)((m_argv.back() == nullptr) ? static_cast<void> (0) : __assert_fail ("m_argv.back() == nullptr", "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Utility/Args.cpp" , 344, __PRETTY_FUNCTION__)); |
345 | |
346 | if (idx >= m_entries.size()) |
347 | return; |
348 | |
349 | if (arg_str.size() > m_entries[idx].ref.size()) { |
350 | m_entries[idx] = ArgEntry(arg_str, quote_char); |
351 | m_argv[idx] = m_entries[idx].data(); |
352 | } else { |
353 | const char *src_data = arg_str.data() ? arg_str.data() : ""; |
354 | ::memcpy(m_entries[idx].data(), src_data, arg_str.size()); |
355 | m_entries[idx].ptr[arg_str.size()] = 0; |
356 | m_entries[idx].ref = m_entries[idx].ref.take_front(arg_str.size()); |
357 | } |
358 | } |
359 | |
360 | void Args::DeleteArgumentAtIndex(size_t idx) { |
361 | if (idx >= m_entries.size()) |
362 | return; |
363 | |
364 | m_argv.erase(m_argv.begin() + idx); |
365 | m_entries.erase(m_entries.begin() + idx); |
366 | } |
367 | |
368 | void Args::SetArguments(size_t argc, const char **argv) { |
369 | Clear(); |
370 | |
371 | auto args = llvm::makeArrayRef(argv, argc); |
372 | m_entries.resize(argc); |
373 | m_argv.resize(argc + 1); |
374 | for (size_t i = 0; i < args.size(); ++i) { |
375 | char quote = |
376 | ((args[i][0] == '\'') || (args[i][0] == '"') || (args[i][0] == '`')) |
377 | ? args[i][0] |
378 | : '\0'; |
379 | |
380 | m_entries[i] = ArgEntry(args[i], quote); |
381 | m_argv[i] = m_entries[i].data(); |
382 | } |
383 | } |
384 | |
385 | void Args::SetArguments(const char **argv) { |
386 | SetArguments(ArgvToArgc(argv), argv); |
387 | } |
388 | |
389 | void Args::Clear() { |
390 | m_entries.clear(); |
391 | m_argv.clear(); |
392 | m_argv.push_back(nullptr); |
393 | } |
394 | |
395 | const char *Args::StripSpaces(std::string &s, bool leading, bool trailing, |
396 | bool return_null_if_empty) { |
397 | static const char *k_white_space = " \t\v"; |
398 | if (!s.empty()) { |
399 | if (leading) { |
400 | size_t pos = s.find_first_not_of(k_white_space); |
401 | if (pos == std::string::npos) |
402 | s.clear(); |
403 | else if (pos > 0) |
404 | s.erase(0, pos); |
405 | } |
406 | |
407 | if (trailing) { |
408 | size_t rpos = s.find_last_not_of(k_white_space); |
409 | if (rpos != std::string::npos && rpos + 1 < s.size()) |
410 | s.erase(rpos + 1); |
411 | } |
412 | } |
413 | if (return_null_if_empty && s.empty()) |
414 | return nullptr; |
415 | return s.c_str(); |
416 | } |
417 | |
418 | const char *Args::GetShellSafeArgument(const FileSpec &shell, |
419 | const char *unsafe_arg, |
420 | std::string &safe_arg) { |
421 | struct ShellDescriptor { |
422 | ConstString m_basename; |
423 | const char *m_escapables; |
424 | }; |
425 | |
426 | static ShellDescriptor g_Shells[] = {{ConstString("bash"), " '\"<>()&"}, |
427 | {ConstString("tcsh"), " '\"<>()&$"}, |
428 | {ConstString("sh"), " '\"<>()&"}}; |
429 | |
430 | // safe minimal set |
431 | const char *escapables = " '\""; |
432 | |
433 | if (auto basename = shell.GetFilename()) { |
434 | for (const auto &Shell : g_Shells) { |
435 | if (Shell.m_basename == basename) { |
436 | escapables = Shell.m_escapables; |
437 | break; |
438 | } |
439 | } |
440 | } |
441 | |
442 | safe_arg.assign(unsafe_arg); |
443 | size_t prev_pos = 0; |
444 | while (prev_pos < safe_arg.size()) { |
445 | // Escape spaces and quotes |
446 | size_t pos = safe_arg.find_first_of(escapables, prev_pos); |
447 | if (pos != std::string::npos) { |
448 | safe_arg.insert(pos, 1, '\\'); |
449 | prev_pos = pos + 2; |
450 | } else |
451 | break; |
452 | } |
453 | return safe_arg.c_str(); |
454 | } |
455 | |
456 | lldb::Encoding Args::StringToEncoding(llvm::StringRef s, |
457 | lldb::Encoding fail_value) { |
458 | return llvm::StringSwitch<lldb::Encoding>(s) |
459 | .Case("uint", eEncodingUint) |
460 | .Case("sint", eEncodingSint) |
461 | .Case("ieee754", eEncodingIEEE754) |
462 | .Case("vector", eEncodingVector) |
463 | .Default(fail_value); |
464 | } |
465 | |
466 | uint32_t Args::StringToGenericRegister(llvm::StringRef s) { |
467 | if (s.empty()) |
468 | return LLDB_INVALID_REGNUM(4294967295U); |
469 | uint32_t result = llvm::StringSwitch<uint32_t>(s) |
470 | .Case("pc", LLDB_REGNUM_GENERIC_PC0) |
471 | .Case("sp", LLDB_REGNUM_GENERIC_SP1) |
472 | .Case("fp", LLDB_REGNUM_GENERIC_FP2) |
473 | .Cases("ra", "lr", LLDB_REGNUM_GENERIC_RA3) |
474 | .Case("flags", LLDB_REGNUM_GENERIC_FLAGS4) |
475 | .Case("arg1", LLDB_REGNUM_GENERIC_ARG15) |
476 | .Case("arg2", LLDB_REGNUM_GENERIC_ARG26) |
477 | .Case("arg3", LLDB_REGNUM_GENERIC_ARG37) |
478 | .Case("arg4", LLDB_REGNUM_GENERIC_ARG48) |
479 | .Case("arg5", LLDB_REGNUM_GENERIC_ARG59) |
480 | .Case("arg6", LLDB_REGNUM_GENERIC_ARG610) |
481 | .Case("arg7", LLDB_REGNUM_GENERIC_ARG711) |
482 | .Case("arg8", LLDB_REGNUM_GENERIC_ARG812) |
483 | .Default(LLDB_INVALID_REGNUM(4294967295U)); |
484 | return result; |
485 | } |
486 | |
487 | void Args::EncodeEscapeSequences(const char *src, std::string &dst) { |
488 | dst.clear(); |
489 | if (src) { |
490 | for (const char *p = src; *p != '\0'; ++p) { |
491 | size_t non_special_chars = ::strcspn(p, "\\"); |
492 | if (non_special_chars > 0) { |
493 | dst.append(p, non_special_chars); |
494 | p += non_special_chars; |
495 | if (*p == '\0') |
496 | break; |
497 | } |
498 | |
499 | if (*p == '\\') { |
500 | ++p; // skip the slash |
501 | switch (*p) { |
502 | case 'a': |
503 | dst.append(1, '\a'); |
504 | break; |
505 | case 'b': |
506 | dst.append(1, '\b'); |
507 | break; |
508 | case 'f': |
509 | dst.append(1, '\f'); |
510 | break; |
511 | case 'n': |
512 | dst.append(1, '\n'); |
513 | break; |
514 | case 'r': |
515 | dst.append(1, '\r'); |
516 | break; |
517 | case 't': |
518 | dst.append(1, '\t'); |
519 | break; |
520 | case 'v': |
521 | dst.append(1, '\v'); |
522 | break; |
523 | case '\\': |
524 | dst.append(1, '\\'); |
525 | break; |
526 | case '\'': |
527 | dst.append(1, '\''); |
528 | break; |
529 | case '"': |
530 | dst.append(1, '"'); |
531 | break; |
532 | case '0': |
533 | // 1 to 3 octal chars |
534 | { |
535 | // Make a string that can hold onto the initial zero char, up to 3 |
536 | // octal digits, and a terminating NULL. |
537 | char oct_str[5] = {'\0', '\0', '\0', '\0', '\0'}; |
538 | |
539 | int i; |
540 | for (i = 0; (p[i] >= '0' && p[i] <= '7') && i < 4; ++i) |
541 | oct_str[i] = p[i]; |
542 | |
543 | // We don't want to consume the last octal character since the main |
544 | // for loop will do this for us, so we advance p by one less than i |
545 | // (even if i is zero) |
546 | p += i - 1; |
547 | unsigned long octal_value = ::strtoul(oct_str, nullptr, 8); |
548 | if (octal_value <= UINT8_MAX(255)) { |
549 | dst.append(1, (char)octal_value); |
550 | } |
551 | } |
552 | break; |
553 | |
554 | case 'x': |
555 | // hex number in the format |
556 | if (isxdigit(p[1])) { |
557 | ++p; // Skip the 'x' |
558 | |
559 | // Make a string that can hold onto two hex chars plus a |
560 | // NULL terminator |
561 | char hex_str[3] = {*p, '\0', '\0'}; |
562 | if (isxdigit(p[1])) { |
563 | ++p; // Skip the first of the two hex chars |
564 | hex_str[1] = *p; |
565 | } |
566 | |
567 | unsigned long hex_value = strtoul(hex_str, nullptr, 16); |
568 | if (hex_value <= UINT8_MAX(255)) |
569 | dst.append(1, (char)hex_value); |
570 | } else { |
571 | dst.append(1, 'x'); |
572 | } |
573 | break; |
574 | |
575 | default: |
576 | // Just desensitize any other character by just printing what came |
577 | // after the '\' |
578 | dst.append(1, *p); |
579 | break; |
580 | } |
581 | } |
582 | } |
583 | } |
584 | } |
585 | |
586 | void Args::ExpandEscapedCharacters(const char *src, std::string &dst) { |
587 | dst.clear(); |
588 | if (src) { |
589 | for (const char *p = src; *p != '\0'; ++p) { |
590 | if (isprint(*p)) |
591 | dst.append(1, *p); |
592 | else { |
593 | switch (*p) { |
594 | case '\a': |
595 | dst.append("\\a"); |
596 | break; |
597 | case '\b': |
598 | dst.append("\\b"); |
599 | break; |
600 | case '\f': |
601 | dst.append("\\f"); |
602 | break; |
603 | case '\n': |
604 | dst.append("\\n"); |
605 | break; |
606 | case '\r': |
607 | dst.append("\\r"); |
608 | break; |
609 | case '\t': |
610 | dst.append("\\t"); |
611 | break; |
612 | case '\v': |
613 | dst.append("\\v"); |
614 | break; |
615 | case '\'': |
616 | dst.append("\\'"); |
617 | break; |
618 | case '"': |
619 | dst.append("\\\""); |
620 | break; |
621 | case '\\': |
622 | dst.append("\\\\"); |
623 | break; |
624 | default: { |
625 | // Just encode as octal |
626 | dst.append("\\0"); |
627 | char octal_str[32]; |
628 | snprintf(octal_str, sizeof(octal_str), "%o", *p); |
629 | dst.append(octal_str); |
630 | } break; |
631 | } |
632 | } |
633 | } |
634 | } |
635 | } |
636 | |
637 | std::string Args::EscapeLLDBCommandArgument(const std::string &arg, |
638 | char quote_char) { |
639 | const char *chars_to_escape = nullptr; |
640 | switch (quote_char) { |
641 | case '\0': |
642 | chars_to_escape = " \t\\'\"`"; |
643 | break; |
644 | case '\'': |
645 | chars_to_escape = ""; |
646 | break; |
647 | case '"': |
648 | chars_to_escape = "$\"`\\"; |
649 | break; |
650 | default: |
651 | assert(false && "Unhandled quote character")((false && "Unhandled quote character") ? static_cast <void> (0) : __assert_fail ("false && \"Unhandled quote character\"" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Utility/Args.cpp" , 651, __PRETTY_FUNCTION__)); |
652 | } |
653 | |
654 | std::string res; |
655 | res.reserve(arg.size()); |
656 | for (char c : arg) { |
657 | if (::strchr(chars_to_escape, c)) |
658 | res.push_back('\\'); |
659 | res.push_back(c); |
660 | } |
661 | return res; |
662 | } |
663 | |
664 | OptionsWithRaw::OptionsWithRaw(llvm::StringRef arg_string) { |
665 | SetFromString(arg_string); |
666 | } |
667 | |
668 | void OptionsWithRaw::SetFromString(llvm::StringRef arg_string) { |
669 | const llvm::StringRef original_args = arg_string; |
670 | |
671 | arg_string = ltrimForArgs(arg_string); |
672 | std::string arg; |
673 | char quote; |
674 | |
675 | // If the string doesn't start with a dash, we just have no options and just |
676 | // a raw part. |
677 | if (!arg_string.startswith("-")) { |
678 | m_suffix = original_args; |
679 | return; |
680 | } |
681 | |
682 | bool found_suffix = false; |
683 | |
684 | while (!arg_string.empty()) { |
685 | // The length of the prefix before parsing. |
686 | std::size_t prev_prefix_length = original_args.size() - arg_string.size(); |
687 | |
688 | // Parse the next argument from the remaining string. |
689 | std::tie(arg, quote, arg_string) = ParseSingleArgument(arg_string); |
690 | |
691 | // If we get an unquoted '--' argument, then we reached the suffix part |
692 | // of the command. |
693 | Args::ArgEntry entry(arg, quote); |
694 | if (!entry.IsQuoted() && arg == "--") { |
695 | // The remaining line is the raw suffix, and the line we parsed so far |
696 | // needs to be interpreted as arguments. |
697 | m_has_args = true; |
698 | m_suffix = arg_string; |
699 | found_suffix = true; |
700 | |
701 | // The length of the prefix after parsing. |
702 | std::size_t prefix_length = original_args.size() - arg_string.size(); |
703 | |
704 | // Take the string we know contains all the arguments and actually parse |
705 | // it as proper arguments. |
706 | llvm::StringRef prefix = original_args.take_front(prev_prefix_length); |
707 | m_args = Args(prefix); |
708 | m_arg_string = prefix; |
709 | |
710 | // We also record the part of the string that contains the arguments plus |
711 | // the delimiter. |
712 | m_arg_string_with_delimiter = original_args.take_front(prefix_length); |
713 | |
714 | // As the rest of the string became the raw suffix, we are done here. |
715 | break; |
716 | } |
717 | |
718 | arg_string = ltrimForArgs(arg_string); |
719 | } |
720 | |
721 | // If we didn't find a suffix delimiter, the whole string is the raw suffix. |
722 | if (!found_suffix) { |
723 | found_suffix = true; |
Value stored to 'found_suffix' is never read | |
724 | m_suffix = original_args; |
725 | } |
726 | } |