reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
  288
  289
  290
  291
  292
  293
  294
  295
  296
  297
  298
  299
  300
  301
  302
  303
  304
  305
  306
  307
  308
  309
  310
  311
  312
  313
  314
  315
  316
  317
  318
  319
  320
  321
  322
  323
  324
  325
  326
  327
  328
  329
  330
  331
  332
  333
  334
  335
  336
  337
  338
  339
  340
  341
  342
  343
  344
  345
  346
  347
  348
  349
  350
  351
  352
  353
  354
  355
  356
  357
  358
  359
  360
  361
  362
  363
  364
  365
  366
  367
  368
  369
  370
  371
  372
  373
  374
  375
  376
  377
  378
  379
  380
  381
  382
  383
  384
  385
  386
  387
  388
  389
  390
  391
  392
  393
  394
  395
  396
  397
  398
  399
  400
  401
  402
  403
  404
  405
//===-- Args.h --------------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_UTILITY_ARGS_H
#define LLDB_UTILITY_ARGS_H

#include "lldb/Utility/Environment.h"
#include "lldb/lldb-private-types.h"
#include "lldb/lldb-types.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include <string>
#include <utility>
#include <vector>

namespace lldb_private {

/// \class Args Args.h "lldb/Utility/Args.h"
/// A command line argument class.
///
/// The Args class is designed to be fed a command line. The command line is
/// copied into an internal buffer and then split up into arguments. Arguments
/// are space delimited if there are no quotes (single, double, or backtick
/// quotes) surrounding the argument. Spaces can be escaped using a \
/// character to avoid having to surround an argument that contains a space
/// with quotes.
class Args {
public:
  struct ArgEntry {
  private:
    friend class Args;
    std::unique_ptr<char[]> ptr;
    char quote;

    char *data() { return ptr.get(); }

  public:
    ArgEntry() = default;
    ArgEntry(llvm::StringRef str, char quote);

    llvm::StringRef ref() const { return c_str(); }
    const char *c_str() const { return ptr.get(); }

    /// Returns true if this argument was quoted in any way.
    bool IsQuoted() const { return quote != '\0'; }
    char GetQuoteChar() const { return quote; }
  };

  /// Construct with an option command string.
  ///
  /// \param[in] command
  ///     A NULL terminated command that will be copied and split up
  ///     into arguments.
  ///
  /// \see Args::SetCommandString(llvm::StringRef)
  Args(llvm::StringRef command = llvm::StringRef());

  Args(const Args &rhs);
  explicit Args(const StringList &list);

  Args &operator=(const Args &rhs);

  /// Destructor.
  ~Args();

  explicit Args(const Environment &env) : Args() {
    SetArguments(const_cast<const char **>(env.getEnvp().get()));
  }

  explicit operator Environment() const { return GetConstArgumentVector(); }

  /// Dump all entries to the stream \a s using label \a label_name.
  ///
  /// If label_name is nullptr, the dump operation is skipped.
  ///
  /// \param[in] s
  ///     The stream to which to dump all arguments in the argument
  ///     vector.
  /// \param[in] label_name
  ///     The label_name to use as the label printed for each
  ///     entry of the args like so:
  ///       {label_name}[{index}]={value}
  void Dump(Stream &s, const char *label_name = "argv") const;

  /// Sets the command string contained by this object.
  ///
  /// The command string will be copied and split up into arguments that can
  /// be accessed via the accessor functions.
  ///
  /// \param[in] command
  ///     A command StringRef that will be copied and split up
  ///     into arguments.
  ///
  /// \see Args::GetArgumentCount() const
  /// \see Args::GetArgumentAtIndex (size_t) const @see
  /// Args::GetArgumentVector () \see Args::Shift () \see Args::Unshift (const
  /// char *)
  void SetCommandString(llvm::StringRef command);

  bool GetCommandString(std::string &command) const;

  bool GetQuotedCommandString(std::string &command) const;

  /// Gets the number of arguments left in this command object.
  ///
  /// \return
  ///     The number or arguments in this object.
  size_t GetArgumentCount() const;
  bool empty() const { return GetArgumentCount() == 0; }

  /// Gets the NULL terminated C string argument pointer for the argument at
  /// index \a idx.
  ///
  /// \return
  ///     The NULL terminated C string argument pointer if \a idx is a
  ///     valid argument index, NULL otherwise.
  const char *GetArgumentAtIndex(size_t idx) const;

  llvm::ArrayRef<ArgEntry> entries() const { return m_entries; }

  using const_iterator = std::vector<ArgEntry>::const_iterator;

  const_iterator begin() const { return m_entries.begin(); }
  const_iterator end() const { return m_entries.end(); }

  size_t size() const { return GetArgumentCount(); }
  const ArgEntry &operator[](size_t n) const { return m_entries[n]; }

  /// Gets the argument vector.
  ///
  /// The value returned by this function can be used by any function that
  /// takes and vector. The return value is just like \a argv in the standard
  /// C entry point function:
  ///     \code
  ///         int main (int argc, const char **argv);
  ///     \endcode
  ///
  /// \return
  ///     An array of NULL terminated C string argument pointers that
  ///     also has a terminating NULL C string pointer
  char **GetArgumentVector();

  /// Gets the argument vector.
  ///
  /// The value returned by this function can be used by any function that
  /// takes and vector. The return value is just like \a argv in the standard
  /// C entry point function:
  ///     \code
  ///         int main (int argc, const char **argv);
  ///     \endcode
  ///
  /// \return
  ///     An array of NULL terminate C string argument pointers that
  ///     also has a terminating NULL C string pointer
  const char **GetConstArgumentVector() const;

  /// Gets the argument as an ArrayRef. Note that the return value does *not*
  /// have a nullptr const char * at the end, as the size of the list is
  /// embedded in the ArrayRef object.
  llvm::ArrayRef<const char *> GetArgumentArrayRef() const {
    return llvm::makeArrayRef(m_argv).drop_back();
  }

  /// Appends a new argument to the end of the list argument list.
  ///
  /// \param[in] arg_str
  ///     The new argument.
  ///
  /// \param[in] quote_char
  ///     If the argument was originally quoted, put in the quote char here.
  void AppendArgument(llvm::StringRef arg_str, char quote_char = '\0');

  void AppendArguments(const Args &rhs);

  void AppendArguments(const char **argv);

  /// Insert the argument value at index \a idx to \a arg_str.
  ///
  /// \param[in] idx
  ///     The index of where to insert the argument.
  ///
  /// \param[in] arg_str
  ///     The new argument.
  ///
  /// \param[in] quote_char
  ///     If the argument was originally quoted, put in the quote char here.
  void InsertArgumentAtIndex(size_t idx, llvm::StringRef arg_str,
                             char quote_char = '\0');

  /// Replaces the argument value at index \a idx to \a arg_str if \a idx is
  /// a valid argument index.
  ///
  /// \param[in] idx
  ///     The index of the argument that will have its value replaced.
  ///
  /// \param[in] arg_str
  ///     The new argument.
  ///
  /// \param[in] quote_char
  ///     If the argument was originally quoted, put in the quote char here.
  void ReplaceArgumentAtIndex(size_t idx, llvm::StringRef arg_str,
                              char quote_char = '\0');

  /// Deletes the argument value at index
  /// if \a idx is a valid argument index.
  ///
  /// \param[in] idx
  ///     The index of the argument that will have its value replaced.
  ///
  void DeleteArgumentAtIndex(size_t idx);

  /// Sets the argument vector value, optionally copying all arguments into an
  /// internal buffer.
  ///
  /// Sets the arguments to match those found in \a argv. All argument strings
  /// will be copied into an internal buffers.
  //
  //  FIXME: Handle the quote character somehow.
  void SetArguments(size_t argc, const char **argv);

  void SetArguments(const char **argv);

  /// Shifts the first argument C string value of the array off the argument
  /// array.
  ///
  /// The string value will be freed, so a copy of the string should be made
  /// by calling Args::GetArgumentAtIndex (size_t) const first and copying the
  /// returned value before calling Args::Shift().
  ///
  /// \see Args::GetArgumentAtIndex (size_t) const
  void Shift();

  /// Inserts a class owned copy of \a arg_str at the beginning of the
  /// argument vector.
  ///
  /// A copy \a arg_str will be made.
  ///
  /// \param[in] arg_str
  ///     The argument to push on the front of the argument stack.
  ///
  /// \param[in] quote_char
  ///     If the argument was originally quoted, put in the quote char here.
  void Unshift(llvm::StringRef arg_str, char quote_char = '\0');

  // Clear the arguments.
  //
  // For re-setting or blanking out the list of arguments.
  void Clear();

  static bool UInt64ValueIsValidForByteSize(uint64_t uval64,
                                            size_t total_byte_size) {
    if (total_byte_size > 8)
      return false;

    if (total_byte_size == 8)
      return true;

    const uint64_t max = (static_cast<uint64_t>(1)
                          << static_cast<uint64_t>(total_byte_size * 8)) -
                         1;
    return uval64 <= max;
  }

  static bool SInt64ValueIsValidForByteSize(int64_t sval64,
                                            size_t total_byte_size) {
    if (total_byte_size > 8)
      return false;

    if (total_byte_size == 8)
      return true;

    const int64_t max = (static_cast<int64_t>(1)
                         << static_cast<uint64_t>(total_byte_size * 8 - 1)) -
                        1;
    const int64_t min = ~(max);
    return min <= sval64 && sval64 <= max;
  }

  static lldb::Encoding
  StringToEncoding(llvm::StringRef s,
                   lldb::Encoding fail_value = lldb::eEncodingInvalid);

  static uint32_t StringToGenericRegister(llvm::StringRef s);

  static const char *GetShellSafeArgument(const FileSpec &shell,
                                          const char *unsafe_arg,
                                          std::string &safe_arg);

  // EncodeEscapeSequences will change the textual representation of common
  // escape sequences like "\n" (two characters) into a single '\n'. It does
  // this for all of the supported escaped sequences and for the \0ooo (octal)
  // and \xXX (hex). The resulting "dst" string will contain the character
  // versions of all supported escape sequences. The common supported escape
  // sequences are: "\a", "\b", "\f", "\n", "\r", "\t", "\v", "\'", "\"", "\\".

  static void EncodeEscapeSequences(const char *src, std::string &dst);

  // ExpandEscapeSequences will change a string of possibly non-printable
  // characters and expand them into text. So '\n' will turn into two
  // characters like "\n" which is suitable for human reading. When a character
  // is not printable and isn't one of the common in escape sequences listed in
  // the help for EncodeEscapeSequences, then it will be encoded as octal.
  // Printable characters are left alone.
  static void ExpandEscapedCharacters(const char *src, std::string &dst);

  static std::string EscapeLLDBCommandArgument(const std::string &arg,
                                               char quote_char);

private:
  std::vector<ArgEntry> m_entries;
  std::vector<char *> m_argv;
};

/// \class OptionsWithRaw Args.h "lldb/Utility/Args.h"
/// A pair of an option list with a 'raw' string as a suffix.
///
/// This class works similar to Args, but handles the case where we have a
/// trailing string that shouldn't be interpreted as a list of arguments but
/// preserved as is. It is also only useful for handling command line options
/// (e.g. '-foo bar -i0') that start with a dash.
///
/// The leading option list is optional. If the first non-space character
/// in the string starts with a dash, and the string contains an argument
/// that is an unquoted double dash (' -- '), then everything up to the double
/// dash is parsed as a list of arguments. Everything after the double dash
/// is interpreted as the raw suffix string. Note that the space behind the
/// double dash is not part of the raw suffix.
///
/// All strings not matching the above format as considered to be just a raw
/// string without any options.
///
/// \see Args
class OptionsWithRaw {
public:
  /// Parse the given string as a list of optional arguments with a raw suffix.
  ///
  /// See the class description for a description of the input format.
  ///
  /// \param[in] argument_string
  ///     The string that should be parsed.
  explicit OptionsWithRaw(llvm::StringRef argument_string);

  /// Returns true if there are any arguments before the raw suffix.
  bool HasArgs() const { return m_has_args; }

  /// Returns the list of arguments.
  ///
  /// You can only call this method if HasArgs returns true.
  Args &GetArgs() {
    assert(m_has_args);
    return m_args;
  }

  /// Returns the list of arguments.
  ///
  /// You can only call this method if HasArgs returns true.
  const Args &GetArgs() const {
    assert(m_has_args);
    return m_args;
  }

  /// Returns the part of the input string that was used for parsing the
  /// argument list. This string also includes the double dash that is used
  /// for separating the argument list from the suffix.
  ///
  /// You can only call this method if HasArgs returns true.
  llvm::StringRef GetArgStringWithDelimiter() const {
    assert(m_has_args);
    return m_arg_string_with_delimiter;
  }

  /// Returns the part of the input string that was used for parsing the
  /// argument list.
  ///
  /// You can only call this method if HasArgs returns true.
  llvm::StringRef GetArgString() const {
    assert(m_has_args);
    return m_arg_string;
  }

  /// Returns the raw suffix part of the parsed string.
  const std::string &GetRawPart() const { return m_suffix; }

private:
  void SetFromString(llvm::StringRef arg_string);

  /// Keeps track if we have parsed and stored any arguments.
  bool m_has_args = false;
  Args m_args;
  llvm::StringRef m_arg_string;
  llvm::StringRef m_arg_string_with_delimiter;

  // FIXME: This should be a StringRef, but some of the calling code expect a
  // C string here so only a real std::string is possible.
  std::string m_suffix;
};

} // namespace lldb_private

#endif // LLDB_UTILITY_ARGS_H