bind.cc 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // Copyright 2020 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "absl/strings/internal/str_format/bind.h"
  15. #include <cerrno>
  16. #include <limits>
  17. #include <sstream>
  18. #include <string>
  19. namespace absl {
  20. ABSL_NAMESPACE_BEGIN
  21. namespace str_format_internal {
  22. namespace {
  23. inline bool BindFromPosition(int position, int* value,
  24. absl::Span<const FormatArgImpl> pack) {
  25. assert(position > 0);
  26. if (static_cast<size_t>(position) > pack.size()) {
  27. return false;
  28. }
  29. // -1 because positions are 1-based
  30. return FormatArgImplFriend::ToInt(pack[position - 1], value);
  31. }
  32. class ArgContext {
  33. public:
  34. explicit ArgContext(absl::Span<const FormatArgImpl> pack) : pack_(pack) {}
  35. // Fill 'bound' with the results of applying the context's argument pack
  36. // to the specified 'unbound'. We synthesize a BoundConversion by
  37. // lining up a UnboundConversion with a user argument. We also
  38. // resolve any '*' specifiers for width and precision, so after
  39. // this call, 'bound' has all the information it needs to be formatted.
  40. // Returns false on failure.
  41. bool Bind(const UnboundConversion* unbound, BoundConversion* bound);
  42. private:
  43. absl::Span<const FormatArgImpl> pack_;
  44. };
  45. inline bool ArgContext::Bind(const UnboundConversion* unbound,
  46. BoundConversion* bound) {
  47. const FormatArgImpl* arg = nullptr;
  48. int arg_position = unbound->arg_position;
  49. if (static_cast<size_t>(arg_position - 1) >= pack_.size()) return false;
  50. arg = &pack_[arg_position - 1]; // 1-based
  51. if (unbound->flags != Flags::kBasic) {
  52. int width = unbound->width.value();
  53. bool force_left = false;
  54. if (unbound->width.is_from_arg()) {
  55. if (!BindFromPosition(unbound->width.get_from_arg(), &width, pack_))
  56. return false;
  57. if (width < 0) {
  58. // "A negative field width is taken as a '-' flag followed by a
  59. // positive field width."
  60. force_left = true;
  61. // Make sure we don't overflow the width when negating it.
  62. width = -std::max(width, -std::numeric_limits<int>::max());
  63. }
  64. }
  65. int precision = unbound->precision.value();
  66. if (unbound->precision.is_from_arg()) {
  67. if (!BindFromPosition(unbound->precision.get_from_arg(), &precision,
  68. pack_))
  69. return false;
  70. }
  71. FormatConversionSpecImplFriend::SetWidth(width, bound);
  72. FormatConversionSpecImplFriend::SetPrecision(precision, bound);
  73. if (force_left) {
  74. FormatConversionSpecImplFriend::SetFlags(unbound->flags | Flags::kLeft,
  75. bound);
  76. } else {
  77. FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound);
  78. }
  79. } else {
  80. FormatConversionSpecImplFriend::SetFlags(unbound->flags, bound);
  81. FormatConversionSpecImplFriend::SetWidth(-1, bound);
  82. FormatConversionSpecImplFriend::SetPrecision(-1, bound);
  83. }
  84. FormatConversionSpecImplFriend::SetConversionChar(unbound->conv, bound);
  85. bound->set_arg(arg);
  86. return true;
  87. }
  88. template <typename Converter>
  89. class ConverterConsumer {
  90. public:
  91. ConverterConsumer(Converter converter, absl::Span<const FormatArgImpl> pack)
  92. : converter_(converter), arg_context_(pack) {}
  93. bool Append(string_view s) {
  94. converter_.Append(s);
  95. return true;
  96. }
  97. bool ConvertOne(const UnboundConversion& conv, string_view conv_string) {
  98. BoundConversion bound;
  99. if (!arg_context_.Bind(&conv, &bound)) return false;
  100. return converter_.ConvertOne(bound, conv_string);
  101. }
  102. private:
  103. Converter converter_;
  104. ArgContext arg_context_;
  105. };
  106. template <typename Converter>
  107. bool ConvertAll(const UntypedFormatSpecImpl format,
  108. absl::Span<const FormatArgImpl> args, Converter converter) {
  109. if (format.has_parsed_conversion()) {
  110. return format.parsed_conversion()->ProcessFormat(
  111. ConverterConsumer<Converter>(converter, args));
  112. } else {
  113. return ParseFormatString(format.str(),
  114. ConverterConsumer<Converter>(converter, args));
  115. }
  116. }
  117. class DefaultConverter {
  118. public:
  119. explicit DefaultConverter(FormatSinkImpl* sink) : sink_(sink) {}
  120. void Append(string_view s) const { sink_->Append(s); }
  121. bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
  122. return FormatArgImplFriend::Convert(*bound.arg(), bound, sink_);
  123. }
  124. private:
  125. FormatSinkImpl* sink_;
  126. };
  127. class SummarizingConverter {
  128. public:
  129. explicit SummarizingConverter(FormatSinkImpl* sink) : sink_(sink) {}
  130. void Append(string_view s) const { sink_->Append(s); }
  131. bool ConvertOne(const BoundConversion& bound, string_view /*conv*/) const {
  132. UntypedFormatSpecImpl spec("%d");
  133. std::ostringstream ss;
  134. ss << "{" << Streamable(spec, {*bound.arg()}) << ":"
  135. << FormatConversionSpecImplFriend::FlagsToString(bound);
  136. if (bound.width() >= 0) ss << bound.width();
  137. if (bound.precision() >= 0) ss << "." << bound.precision();
  138. ss << bound.conversion_char() << "}";
  139. Append(ss.str());
  140. return true;
  141. }
  142. private:
  143. FormatSinkImpl* sink_;
  144. };
  145. } // namespace
  146. bool BindWithPack(const UnboundConversion* props,
  147. absl::Span<const FormatArgImpl> pack,
  148. BoundConversion* bound) {
  149. return ArgContext(pack).Bind(props, bound);
  150. }
  151. std::string Summarize(const UntypedFormatSpecImpl format,
  152. absl::Span<const FormatArgImpl> args) {
  153. typedef SummarizingConverter Converter;
  154. std::string out;
  155. {
  156. // inner block to destroy sink before returning out. It ensures a last
  157. // flush.
  158. FormatSinkImpl sink(&out);
  159. if (!ConvertAll(format, args, Converter(&sink))) {
  160. return "";
  161. }
  162. }
  163. return out;
  164. }
  165. bool FormatUntyped(FormatRawSinkImpl raw_sink,
  166. const UntypedFormatSpecImpl format,
  167. absl::Span<const FormatArgImpl> args) {
  168. FormatSinkImpl sink(raw_sink);
  169. using Converter = DefaultConverter;
  170. return ConvertAll(format, args, Converter(&sink));
  171. }
  172. std::ostream& Streamable::Print(std::ostream& os) const {
  173. if (!FormatUntyped(&os, format_, args_)) os.setstate(std::ios::failbit);
  174. return os;
  175. }
  176. std::string& AppendPack(std::string* out, const UntypedFormatSpecImpl format,
  177. absl::Span<const FormatArgImpl> args) {
  178. size_t orig = out->size();
  179. if (ABSL_PREDICT_FALSE(!FormatUntyped(out, format, args))) {
  180. out->erase(orig);
  181. }
  182. return *out;
  183. }
  184. std::string FormatPack(const UntypedFormatSpecImpl format,
  185. absl::Span<const FormatArgImpl> args) {
  186. std::string out;
  187. if (ABSL_PREDICT_FALSE(!FormatUntyped(&out, format, args))) {
  188. out.clear();
  189. }
  190. return out;
  191. }
  192. int FprintF(std::FILE* output, const UntypedFormatSpecImpl format,
  193. absl::Span<const FormatArgImpl> args) {
  194. FILERawSink sink(output);
  195. if (!FormatUntyped(&sink, format, args)) {
  196. errno = EINVAL;
  197. return -1;
  198. }
  199. if (sink.error()) {
  200. errno = sink.error();
  201. return -1;
  202. }
  203. if (sink.count() > static_cast<size_t>(std::numeric_limits<int>::max())) {
  204. errno = EFBIG;
  205. return -1;
  206. }
  207. return static_cast<int>(sink.count());
  208. }
  209. int SnprintF(char* output, size_t size, const UntypedFormatSpecImpl format,
  210. absl::Span<const FormatArgImpl> args) {
  211. BufferRawSink sink(output, size ? size - 1 : 0);
  212. if (!FormatUntyped(&sink, format, args)) {
  213. errno = EINVAL;
  214. return -1;
  215. }
  216. size_t total = sink.total_written();
  217. if (size) output[std::min(total, size - 1)] = 0;
  218. return static_cast<int>(total);
  219. }
  220. } // namespace str_format_internal
  221. ABSL_NAMESPACE_END
  222. } // namespace absl