00001 #include "absl/strings/internal/str_format/bind.h"
00002
00003 #include <cerrno>
00004 #include <limits>
00005 #include <sstream>
00006 #include <string>
00007
00008 namespace absl {
00009 namespace str_format_internal {
00010
00011 namespace {
00012
00013 inline bool BindFromPosition(int position, int* value,
00014 absl::Span<const FormatArgImpl> pack) {
00015 assert(position > 0);
00016 if (static_cast<size_t>(position) > pack.size()) {
00017 return false;
00018 }
00019
00020 return FormatArgImplFriend::ToInt(pack[position - 1], value);
00021 }
00022
00023 class ArgContext {
00024 public:
00025 explicit ArgContext(absl::Span<const FormatArgImpl> pack) : pack_(pack) {}
00026
00027
00028
00029
00030
00031
00032
00033 bool Bind(const UnboundConversion* unbound, BoundConversion* bound);
00034
00035 private:
00036 absl::Span<const FormatArgImpl> pack_;
00037 };
00038
00039 inline bool ArgContext::Bind(const UnboundConversion* unbound,
00040 BoundConversion* bound) {
00041 const FormatArgImpl* arg = nullptr;
00042 int arg_position = unbound->arg_position;
00043 if (static_cast<size_t>(arg_position - 1) >= pack_.size()) return false;
00044 arg = &pack_[arg_position - 1];
00045
00046 if (!unbound->flags.basic) {
00047 int width = unbound->width.value();
00048 bool force_left = false;
00049 if (unbound->width.is_from_arg()) {
00050 if (!BindFromPosition(unbound->width.get_from_arg(), &width, pack_))
00051 return false;
00052 if (width < 0) {
00053
00054
00055 force_left = true;
00056
00057 width = -std::max(width, -std::numeric_limits<int>::max());
00058 }
00059 }
00060
00061 int precision = unbound->precision.value();
00062 if (unbound->precision.is_from_arg()) {
00063 if (!BindFromPosition(unbound->precision.get_from_arg(), &precision,
00064 pack_))
00065 return false;
00066 }
00067
00068 bound->set_width(width);
00069 bound->set_precision(precision);
00070 bound->set_flags(unbound->flags);
00071 if (force_left)
00072 bound->set_left(true);
00073 } else {
00074 bound->set_flags(unbound->flags);
00075 bound->set_width(-1);
00076 bound->set_precision(-1);
00077 }
00078
00079 bound->set_length_mod(unbound->length_mod);
00080 bound->set_conv(unbound->conv);
00081 bound->set_arg(arg);
00082 return true;
00083 }
00084
00085 template <typename Converter>
00086 class ConverterConsumer {
00087 public:
00088 ConverterConsumer(Converter converter, absl::Span<const FormatArgImpl> pack)
00089 : converter_(converter), arg_context_(pack) {}
00090
00091 bool Append(string_view s) {
00092 converter_.Append(s);
00093 return true;
00094 }
00095 bool ConvertOne(const UnboundConversion& conv, string_view conv_string) {
00096 BoundConversion bound;
00097 if (!arg_context_.Bind(&conv, &bound)) return false;
00098 return converter_.ConvertOne(bound, conv_string);
00099 }
00100
00101 private:
00102 Converter converter_;
00103 ArgContext arg_context_;
00104 };
00105
00106 template <typename Converter>
00107 bool ConvertAll(const UntypedFormatSpecImpl format,
00108 absl::Span<const FormatArgImpl> args, Converter converter) {
00109 if (format.has_parsed_conversion()) {
00110 return format.parsed_conversion()->ProcessFormat(
00111 ConverterConsumer<Converter>(converter, args));
00112 } else {
00113 return ParseFormatString(format.str(),
00114 ConverterConsumer<Converter>(converter, args));
00115 }
00116 }
00117
00118 class DefaultConverter {
00119 public:
00120 explicit DefaultConverter(FormatSinkImpl* sink) : sink_(sink) {}
00121
00122 void Append(string_view s) const { sink_->Append(s); }
00123
00124 bool ConvertOne(const BoundConversion& bound, string_view ) const {
00125 return FormatArgImplFriend::Convert(*bound.arg(), bound, sink_);
00126 }
00127
00128 private:
00129 FormatSinkImpl* sink_;
00130 };
00131
00132 class SummarizingConverter {
00133 public:
00134 explicit SummarizingConverter(FormatSinkImpl* sink) : sink_(sink) {}
00135
00136 void Append(string_view s) const { sink_->Append(s); }
00137
00138 bool ConvertOne(const BoundConversion& bound, string_view ) const {
00139 UntypedFormatSpecImpl spec("%d");
00140
00141 std::ostringstream ss;
00142 ss << "{" << Streamable(spec, {*bound.arg()}) << ":" << bound.flags();
00143 if (bound.width() >= 0) ss << bound.width();
00144 if (bound.precision() >= 0) ss << "." << bound.precision();
00145 ss << bound.length_mod() << bound.conv() << "}";
00146 Append(ss.str());
00147 return true;
00148 }
00149
00150 private:
00151 FormatSinkImpl* sink_;
00152 };
00153
00154 }
00155
00156 bool BindWithPack(const UnboundConversion* props,
00157 absl::Span<const FormatArgImpl> pack,
00158 BoundConversion* bound) {
00159 return ArgContext(pack).Bind(props, bound);
00160 }
00161
00162 std::string Summarize(const UntypedFormatSpecImpl format,
00163 absl::Span<const FormatArgImpl> args) {
00164 typedef SummarizingConverter Converter;
00165 std::string out;
00166 {
00167
00168
00169 FormatSinkImpl sink(&out);
00170 if (!ConvertAll(format, args, Converter(&sink))) {
00171 return "";
00172 }
00173 }
00174 return out;
00175 }
00176
00177 bool FormatUntyped(FormatRawSinkImpl raw_sink,
00178 const UntypedFormatSpecImpl format,
00179 absl::Span<const FormatArgImpl> args) {
00180 FormatSinkImpl sink(raw_sink);
00181 using Converter = DefaultConverter;
00182 return ConvertAll(format, args, Converter(&sink));
00183 }
00184
00185 std::ostream& Streamable::Print(std::ostream& os) const {
00186 if (!FormatUntyped(&os, format_, args_)) os.setstate(std::ios::failbit);
00187 return os;
00188 }
00189
00190 std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl format,
00191 absl::Span<const FormatArgImpl> args) {
00192 size_t orig = out->size();
00193 if (ABSL_PREDICT_FALSE(!FormatUntyped(out, format, args))) {
00194 out->erase(orig);
00195 }
00196 return *out;
00197 }
00198
00199 int FprintF(std::FILE* output, const UntypedFormatSpecImpl format,
00200 absl::Span<const FormatArgImpl> args) {
00201 FILERawSink sink(output);
00202 if (!FormatUntyped(&sink, format, args)) {
00203 errno = EINVAL;
00204 return -1;
00205 }
00206 if (sink.error()) {
00207 errno = sink.error();
00208 return -1;
00209 }
00210 if (sink.count() > std::numeric_limits<int>::max()) {
00211 errno = EFBIG;
00212 return -1;
00213 }
00214 return static_cast<int>(sink.count());
00215 }
00216
00217 int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl format,
00218 absl::Span<const FormatArgImpl> args) {
00219 BufferRawSink sink(output, size ? size - 1 : 0);
00220 if (!FormatUntyped(&sink, format, args)) {
00221 errno = EINVAL;
00222 return -1;
00223 }
00224 size_t total = sink.total_written();
00225 if (size) output[std::min(total, size - 1)] = 0;
00226 return static_cast<int>(total);
00227 }
00228
00229 }
00230 }