| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 | #include "absl/strings/internal/str_format/bind.h"#include <cerrno>#include <limits>#include <sstream>#include <string>namespace absl {ABSL_NAMESPACE_BEGINnamespace str_format_internal {namespace {inline bool BindFromPosition(int position, int* value,                             absl::Span<const FormatArgImpl> pack) {  assert(position > 0);  if (static_cast<size_t>(position) > pack.size()) {    return false;  }  // -1 because positions are 1-based  return FormatArgImplFriend::ToInt(pack[position - 1], value);}class ArgContext { public:  explicit ArgContext(absl::Span<const FormatArgImpl> pack) : pack_(pack) {}  // Fill 'bound' with the results of applying the context's argument pack  // to the specified 'unbound'. We synthesize a BoundConversion by  // lining up a UnboundConversion with a user argument. We also  // resolve any '*' specifiers for width and precision, so after  // this call, 'bound' has all the information it needs to be formatted.  // Returns false on failure.  bool Bind(const UnboundConversion* unbound, BoundConversion* bound); private:  absl::Span<const FormatArgImpl> pack_;};inline bool ArgContext::Bind(const UnboundConversion* unbound,                             BoundConversion* bound) {  const FormatArgImpl* arg = nullptr;  int arg_position = unbound->arg_position;  if (static_cast<size_t>(arg_position - 1) >= pack_.size()) return false;  arg = &pack_[arg_position - 1];  // 1-based  if (!unbound->flags.basic) {    int width = unbound->width.value();    bool force_left = false;    if (unbound->width.is_from_arg()) {      if (!BindFromPosition(unbound->width.get_from_arg(), &width, pack_))        return false;      if (width < 0) {        // "A negative field width is taken as a '-' flag followed by a        // positive field width."        force_left = true;        // Make sure we don't overflow the width when negating it.        width = -std::max(width, -std::numeric_limits<int>::max());      }    }    int precision = unbound->precision.value();    if (unbound->precision.is_from_arg()) {      if (!BindFromPosition(unbound->precision.get_from_arg(), &precision,                            pack_))        return false;    }    FormatConversionSpecImplFriend::SetWidth(width, bound);    FormatConversionSpecImplFriend::SetPrecision(precision, bound);    if (force_left) {      Flags flags = unbound->flags;      flags.left = true;      FormatConversionSpecImplFriend::SetFlags(flags, bound);    } else {      FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound);    }  } else {    FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound);    FormatConversionSpecImplFriend::SetWidth(-1, bound);    FormatConversionSpecImplFriend::SetPrecision(-1, bound);  }  FormatConversionSpecImplFriend::SetConversionChar(unbound->conv, bound);  bound->set_arg(arg);  return true;}template <typename Converter>class ConverterConsumer { public:  ConverterConsumer(Converter converter, absl::Span<const FormatArgImpl> pack)      : converter_(converter), arg_context_(pack) {}  bool Append(string_view s) {    converter_.Append(s);    return true;  }  bool ConvertOne(const UnboundConversion& conv, string_view conv_string) {    BoundConversion bound;    if (!arg_context_.Bind(&conv, &bound)) return false;    return converter_.ConvertOne(bound, conv_string);  } private:  Converter converter_;  ArgContext arg_context_;};template <typename Converter>bool ConvertAll(const UntypedFormatSpecImpl format,                absl::Span<const FormatArgImpl> args, Converter converter) {  if (format.has_parsed_conversion()) {    return format.parsed_conversion()->ProcessFormat(        ConverterConsumer<Converter>(converter, args));  } else {    return ParseFormatString(format.str(),                             ConverterConsumer<Converter>(converter, args));  }}class DefaultConverter { public:  explicit DefaultConverter(FormatSinkImpl* sink) : sink_(sink) {}  void Append(string_view s) const { sink_->Append(s); }  bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {    return FormatArgImplFriend::Convert(*bound.arg(), bound, sink_);  } private:  FormatSinkImpl* sink_;};class SummarizingConverter { public:  explicit SummarizingConverter(FormatSinkImpl* sink) : sink_(sink) {}  void Append(string_view s) const { sink_->Append(s); }  bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {    UntypedFormatSpecImpl spec("%d");    std::ostringstream ss;    ss << "{" << Streamable(spec, {*bound.arg()}) << ":"       << FormatConversionSpecImplFriend::FlagsToString(bound);    if (bound.width() >= 0) ss << bound.width();    if (bound.precision() >= 0) ss << "." << bound.precision();    ss << bound.conversion_char() << "}";    Append(ss.str());    return true;  } private:  FormatSinkImpl* sink_;};}  // namespacebool BindWithPack(const UnboundConversion* props,                  absl::Span<const FormatArgImpl> pack,                  BoundConversion* bound) {  return ArgContext(pack).Bind(props, bound);}std::string Summarize(const UntypedFormatSpecImpl format,                      absl::Span<const FormatArgImpl> args) {  typedef SummarizingConverter Converter;  std::string out;  {    // inner block to destroy sink before returning out. It ensures a last    // flush.    FormatSinkImpl sink(&out);    if (!ConvertAll(format, args, Converter(&sink))) {      return "";    }  }  return out;}bool FormatUntyped(FormatRawSinkImpl raw_sink,                   const UntypedFormatSpecImpl format,                   absl::Span<const FormatArgImpl> args) {  FormatSinkImpl sink(raw_sink);  using Converter = DefaultConverter;  return ConvertAll(format, args, Converter(&sink));}std::ostream& Streamable::Print(std::ostream& os) const {  if (!FormatUntyped(&os, format_, args_)) os.setstate(std::ios::failbit);  return os;}std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl format,                        absl::Span<const FormatArgImpl> args) {  size_t orig = out->size();  if (ABSL_PREDICT_FALSE(!FormatUntyped(out, format, args))) {    out->erase(orig);  }  return *out;}std::string FormatPack(const UntypedFormatSpecImpl format,                       absl::Span<const FormatArgImpl> args) {  std::string out;  if (ABSL_PREDICT_FALSE(!FormatUntyped(&out, format, args))) {    out.clear();  }  return out;}int FprintF(std::FILE* output, const UntypedFormatSpecImpl format,            absl::Span<const FormatArgImpl> args) {  FILERawSink sink(output);  if (!FormatUntyped(&sink, format, args)) {    errno = EINVAL;    return -1;  }  if (sink.error()) {    errno = sink.error();    return -1;  }  if (sink.count() > std::numeric_limits<int>::max()) {    errno = EFBIG;    return -1;  }  return static_cast<int>(sink.count());}int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl format,             absl::Span<const FormatArgImpl> args) {  BufferRawSink sink(output, size ? size - 1 : 0);  if (!FormatUntyped(&sink, format, args)) {    errno = EINVAL;    return -1;  }  size_t total = sink.total_written();  if (size) output[std::min(total, size - 1)] = 0;  return static_cast<int>(total);}}  // namespace str_format_internalABSL_NAMESPACE_END}  // namespace absl
 |