void AMXStackFramePrinter::PrintArgumentValue(const AMXStackFrame &frame,
                                              const AMXDebugSymbol &arg,
                                              int index) {
  std::string tag_name = debug_info_.GetTagName(arg.GetTag());
  cell value = GetArgumentValue(frame, index);

  if (arg.IsVariable()) {
    PrintValue(tag_name, value);
    return;
  }

  stream_ << "@";
  PrintAddress(value);

  if (arg.IsReference()) {
    if (cell *ptr = GetDataPtr(frame.amx(), value)) {
      stream_ << " ";
      PrintValue(tag_name, *ptr);
    }
    return;
  }

  if (arg.IsArray() || arg.IsArrayRef()) {
    std::vector<AMXDebugSymbolDim> dims = arg.GetDims();

    // Try to filter out non-printable arrays (e.g. non-strings).
    // This doesn't work 100% of the time, but it's better than nothing.
    if (dims.size() == 1
        && tag_name == "_"
        && debug_info_.GetTagName(dims[0].GetTag()) == "_")
    {
      std::string string;
      bool packed;

      GetStringContents(frame.amx(), value, dims[0].GetSize(), string, packed);
      stream_ << (packed ? " !" : " ");

      static const std::size_t kMaxString = 80;
      if (string.length() > kMaxString) {
        string.replace(kMaxString, string.length() - kMaxString, "...");
      }

      stream_ << "\"" << string << "\"";
    }
  }
}
void AMXStackFramePrinter::PrintArgumentValue(const AMXStackFrame &frame,
                                              const AMXDebugSymbol &arg,
                                              int index) {
  std::string tag_name = debug_info_->GetTagName(arg.GetTag());
  cell value = GetArgumentValue(frame.amx(), frame.address(), index);

  if (arg.IsVariable()) {
    if (tag_name == "bool") {
      *stream_ << (value ? "true" : "false");
    } else if (tag_name == "Float") {
      *stream_ << std::fixed << std::setprecision(5) << amx_ctof(value);
    } else {
      *stream_ << value;
    }
  } else {
    std::vector<AMXDebugSymbolDim> dims = arg.GetDims();

    // For arrays/references we just output their AMX address.
    char old_fill = stream_->fill('0');
    *stream_ << "@0x" << std::hex << std::setw(kCellWidthChars)
             << value << std::dec;
    stream_->fill(old_fill);

    if ((arg.IsArray() || arg.IsArrayRef())
        && dims.size() == 1
        && tag_name == "_"
        && debug_info_->GetTagName(dims[0].GetTag()) == "_")
    {
      std::string string;
      bool packed;
      
      GetStringContents(frame.amx(), value, dims[0].GetSize(), string, packed);
      *stream_ << (packed ? " !" : " ");
      
      static const std::size_t kMaxString = 30;
      if (string.length() > kMaxString) {
        string.replace(kMaxString, string.length() - kMaxString, "...");
      }
      
      *stream_ << "\"" << string << "\"";
    }
  }
}
void AMXStackFramePrinter::PrintTag(const AMXDebugSymbol &symbol) {
  std::string tag_name = debug_info_->GetTagName(symbol.GetTag());
  if (!tag_name.empty() && tag_name != "_") {
    *stream_ << tag_name << ":";
  }
}