void AMXStackFramePrinter::PrintCallerName(const AMXStackFrame &frame) {
  if (IsMain(frame.amx(), frame.caller_address())) {
    stream_ << "main";
    return;
  }

  if (debug_info_.IsLoaded()) {
    AMXDebugSymbol caller =
      debug_info_.GetExactFunction(frame.caller_address());
    if (caller) {
      if (IsPublicFunction(frame.amx(), caller.GetCodeStart())
          && !IsMain(frame.amx(), caller.GetCodeStart())) {
        stream_ << "public ";
      }
      PrintTag(caller);
      stream_ << caller.GetName();
      return;
    }
  }

  const char *name = 0;
  if (frame.caller_address() != 0) {
    name = frame.amx().FindPublic(frame.caller_address());
  }
  if (name != 0) {
    stream_ << "public " << name;
  } else {
    stream_ << "??";
  }
}
void AMXStackFramePrinter::PrintArgumentList(const AMXStackFrame &frame) {
  AMXStackFrame prev_frame = frame.GetPrevious();

  if (prev_frame) {
    // Although the symbol's code start address points at the state
    // switch code block, function arguments actually use the real
    // function address for the code start because in different states
    // they may be not the same.
    cell arg_address = frame.caller_address();
    if (UsesAutomata(frame)) {
      arg_address = GetRealFunctionAddress(frame.amx(), frame.caller_address(),
                                                        frame.return_address());
    }

    std::vector<AMXDebugSymbol> args;
    int num_actual_args = 0;

    if (HaveDebugInfo()) {
      std::remove_copy_if(debug_info_->GetSymbols().begin(),
                          debug_info_->GetSymbols().end(),
                          std::back_inserter(args),
                          std::not1(IsArgumentOf(arg_address)));
      std::sort(args.begin(), args.end());
      num_actual_args = static_cast<int>(args.size());
    } else {
      static const int kMaxRawArgs = 10;
      num_actual_args = std::min(kMaxRawArgs,
                                 GetNumArgs(frame.amx(), prev_frame.address()));
    }

    // Print a comma-separated list of arguments and their values.
    // If debug info is not available argument names are omitted,
    // so only the values are printed.
    for (int i = 0; i < num_actual_args; i++) {
      if (i > 0) {
        *stream_ << ", ";
      }
      if (HaveDebugInfo()) {
        PrintArgument(prev_frame, args[i], i);
      } else {
        PrintArgument(prev_frame, i);
      }
    }

    // If the number of actual arguments passed to the function exceeds
    // that obtained via debug info the function may take a variable
    // number of arguments. In this case we don't evaluate them but just
    // just say that they are present as we can't say anything about
    // their names and types.
    int num_var_args = GetNumArgs(frame.amx(), prev_frame.address())
                     - num_actual_args;
    if (num_var_args > 0) {
      if (num_actual_args != 0) {
        *stream_ << ", ";
      }
      PrintVariableArguments(num_var_args);
    }
  }
}
void AMXStackFramePrinter::PrintCallerName(const AMXStackFrame &frame) {
  if (IsMain(frame.amx(), frame.caller_address())) {
    *stream_ << "main";
  } else {
    const char *name = 0;
    if (frame.caller_address() != 0) {
      name = frame.amx().FindPublic(frame.caller_address());
    }
    if (name != 0) {
      *stream_ << "public " << name;
    } else {
      *stream_ << "??";
    }
  }
}
AMXDebugSymbol AMXStackFramePrinter::GetCallerSymbol(
                                            const AMXStackFrame &frame) const {
  AMXDebugSymbol caller;
  if (HaveDebugInfo()) {
    caller = debug_info_->GetExactFunction(frame.caller_address());
  }
  return caller;
}
void AMXStackFramePrinter::PrintState(const AMXStackFrame &frame) {
  AMXDebugAutomaton automaton = debug_info_->GetAutomaton(
    GetStateVarAddress(frame.amx(), frame.caller_address()));
  if (automaton) {
    std::vector<cell> states = GetStateIDs(frame.amx(), frame.caller_address(),
                                                        frame.return_address());
    if (!states.empty()) {
      *stream_ << "<" << automaton.GetName() << ":";
      for (std::size_t i = 0; i < states.size(); i++ ) {
        if (i > 0) {
          *stream_ << ", ";
        }
        AMXDebugState state = debug_info_->GetState(automaton.GetID(), states[i]);
        if (state) {
          *stream_ << state.GetName();
        }
      }
      *stream_ << ">";
    }
  }
}
bool AMXStackFramePrinter::UsesAutomata(const AMXStackFrame &frame) const {
  return GetStateVarAddress(frame.amx(), frame.caller_address()) > 0;
}